В этом коде я получаю другое значение sizeof(T), если распределитель является частью выделения контейнера:
#include <iostream>
#include <set>
#include <cstddef>
class Item
{
int a;
unsigned char b, c, d;
int e, f, g;
public:
Item() { a = b = c = d = e = f = g = 0; }
bool operator<(const Item& item) const { return item.a < a; }
};
template <typename T> class TestAllocator
{
public:
typedef T value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
pointer address(reference x) const { return &x; }
const_pointer address(const_reference x) const { return &x; }
TestAllocator() { std::cout << "TestAllocator ctor: sizeof T:" << sizeof(T) << std::endl; }
template <typename U> TestAllocator(const TestAllocator<U>&) {}
~TestAllocator() {}
pointer allocate(size_type /*n*/, void * = 0) { return static_cast<T*>(new T()); }
void deallocate(pointer p, size_type /*n*/) { delete p; }
TestAllocator<T>& operator=(const TestAllocator&) { return *this; }
void construct(pointer p, const T& val) { new ((T*) p) T(val); }
void destroy(pointer p) { p->~T(); }
size_type max_size() const { return size_t(-1); }
template <typename U> struct rebind { typedef TestAllocator<U> other; };
template <typename U> TestAllocator& operator=(const TestAllocator<U>&) { return *this; }
};
typedef std::multiset<Item, std::less<Item>, TestAllocator<Item> > ItemMultiset;
int main(int /*argc*/, char** /*argv*/)
{
std::cout << "Instantiating allocator:" << std::endl;
TestAllocator<Item> ta;
std::cout << "Instantiating container:" << std::endl;
ItemMultiset ims;
return 0;
}
Здесь на моем gcc 7.2.1 я получаю:
Instantiating allocator:
TestAllocator ctor: sizeof T:20
Instantiating container:
TestAllocator ctor: sizeof T:56
Результаты некоторых онлайн-компиляторов:
VC++ на webcompiler.cloudapp.net сказал 20 и 36.
Колиру на coliru.stacked-crooked.com сказал 20 и 56 для всех выбранных компиляторов gcc, 20 и 56 для clang 3.8 или 20 и 48 для clang 3.8 C++ 11/14.
В чем разница и почему некоторые результаты дополняют каждый член структуры?
Как я могу узнать, в каком «режиме» выравнивания находится контейнер, и применить его к моей структуре или коду, или как я могу указать контейнеру использовать режим моего кода, чтобы результаты всегда были идентичными?
РЕДАКТИРОВАТЬ: Спасибо за быстрый ответ ниже.
Вау, много места использовано. Дальнейшие результаты с другими контейнерами:
Instantiating allocator:
TestAllocator ctor: sizeof T:20
Instantiating multiset:
TestAllocator ctor: sizeof T:56
Instantiating multimap:
TestAllocator ctor: sizeof T:20
Instantiating list:
TestAllocator ctor: sizeof T:40
Instantiating vector:
TestAllocator ctor: sizeof T:20
РЕДАКТИРОВАТЬ 2:
В интересах тех, кто работает с пулами распределения:
Ура! Думаю, я достиг своей цели. Пример кода основан на реальном приложении, и, как и следовало ожидать, allocate
и deallocate
шаблона распределителя не просто вызывают new
и delete
. они передают в пул. До четверга пул представлял собой глобальный многомерный стиль фрагментирования (несколько разных плоскостей для общих запросов ожидаемого размера). allocate
передаст требуемое количество байтов. Затем я шаблонизировал наш глобальный пул, но как-то неуклюже глобальный экземпляр нужно было отдельно инициализировать с нужным типом — вот тут-то и начались проблемы, это не тот тип! Я увидел возможность для allocate
передавать только количество элементов вместо байтов. Как вы видели, это не сработало так, как я пытался. Моя ошибка заключалась в том, что вскоре после шаблонизации нашего пула я не понял, что могу просто поместить его статический экземпляр в свой класс шаблонов распределителя. Бум, проблема решена, теперь все размеры совпадают. Пул теперь работает нормально, теперь это шаблон, встроенный в класс шаблона распределителя, и он более компактен и эффективен, чем наша предыдущая версия. ~25 лет с C++, шаблоны не перестают меня удивлять. Спасибо за вашу помощь.