LINUX.ORG.RU

стандартный аллокатор и выравнивание

 


0

3
template <typename _Tp>
struct FooStruct {
  __attribute__((aligned(16))) _Tp bar[256];
};

template <typename _Tp> class FooClass {
private:
  std::allocator<_Tp> alloc;
  FooStruct* ptr;

public:
  FooClass() { ptr = static_cast<FooStruct*>(alloc.allocate(256)); }
  ~FooClass() { alloc.deallocate(static_cast<_Tp*>(ptr), 256); }
};

Будет ли bar выровнен по 16?


В общем случае нет, у тебя же аллокатор для _Tp, а он ничего не знает про выравнивание FooStruct.

mix_mix ★★★★★
()

Даже если бы знал - он должен быть выровнен согласно здравому смыслу и согласно

http://en.cppreference.com/w/cpp/memory/allocator/allocate

Однако баги никто не отменял, и похоже что для gcc стандартный аллокатор в конце концов использует

/usr/include/c++/4.9/ext/new_allocator.h

в котором написано пугающее

return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));

То есть информация о выравнивании тут теряется, если только конкретная реализация new, не будет гарантировать что выделяет блок выровненный согласно максимальной степени 2, делящей размер.

На практике почти на любой 64-битной системе на 16 будет выровнен практически любой блок, так что баги могут посыпаться очень не сразу и внезапно, когда это по каким-то причинам нарушится.

Костыль с std::aligned_alloc и alignof может помочь.

К слову не очень ясно какие максимальные пределы для X в __attribute__((aligned(X))) и как система должна рапортавать что они не поддерживаются.

GPFault ★★
()
Ответ на: комментарий от mix_mix

тогда другая опция:

template <typename _Tp> class FooClass {
private:
  std::allocator<FooStruct> alloc;
  FooStruct* ptr;

public:
  FooClass() { ptr = alloc.allocate(1); }
  ~FooClass() { alloc.deallocate(ptr, 1); }
};

Вопрос тот же.

geks
() автор топика
Ответ на: комментарий от anonymous

А что не так?

То есть информация о выравнивании тут теряется, если только конкретная реализация new, не будет гарантировать что выделяет блок выровненный согласно максимальной степени 2, делящей размер.

mix_mix ★★★★★
()
Ответ на: комментарий от GPFault

К слову не очень ясно какие максимальные пределы для X в __attribute__((aligned(X))) и как система должна рапортавать что они не поддерживаются.

A fundamental alignment is represented by an alignment less than or equal to the greatest alignment supported by the implementation in all contexts, which is equal to alignof(std::max_align_t) (18.2).

An extended alignment is represented by an alignment greater than alignof(std::max_align_t). It is implementation-defined whether any extended alignments are supported and the contexts in which they are supported (7.6.2).

Valid alignments include only those values returned by an alignof expression for the fundamental types plus an additional implementation-defined set of values, which may be empty. Every alignment value shall be a non-negative integral power of two.

If a request for a specific extended alignment in a specific context is not supported by an implementation, the program is ill-formed. Additionally, a request for runtime allocation of dynamic storage for which the requested alignment cannot be honored shall be treated as an allocation failure.
Pavval ★★★★★
()
Последнее исправление: Pavval (всего исправлений: 1)
Ответ на: комментарий от geks

Должно быть выровняно. Аллокатору предоставлена вся инфа и он должен вызывать std::align(), чтобы выровнять объект в выделенной памяти.

pointer allocate(size_type n, allocator<void>::const_pointer hint = 0);
Returns: A pointer to the initial element of an array of storage of size n * sizeof(T), aligned appropriately for objects of type T. It is implementation-defined whether over-aligned types are supported (3.11).
Pavval ★★★★★
()

в amd64 c++ abi явно указано, что любой массив, который по факту занимает не меньше 16 байт будет выровнен по 16-байтной границе.

сам пользовался. брат пока жив.

и да, так же не переносимо как и gcc-измы.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.