为什么我的容器分配器中的 sizeof(T) 与单独的分配器中的 sizeof(T) 不同?

Why is sizeof(T) different inside my container allocator than in the allocator alone?

本文关键字:sizeof 分配器 单独 不同 我的 为什么      更新时间:2023-10-16

在此代码中,如果分配器 是容器分配的一部分:

#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 编译器,Clang 3.8 为 20 和 56, 或 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:

为了使用分配池的用户的利益:

耶!我想我实现了我的目标。示例代码基于 在实际应用程序上,正如您所料,分配器模板的allocatedeallocate不只是打电话给newdelete. 他们交给游泳池。直到周四,游泳池还是全球的 分块样式多维(几个不同的平面 对于常见的预期大小请求)。allocate会过去的 所需的字节数。然后我模板化了我们的 全局池,但全局实例必须有点笨拙 使用所需的类型单独初始化 - 这就是 麻烦开始了,那不是正确的类型!我看到了一个机会allocate仅传递项目数而不是字节数。 正如你所看到的,它没有按照我尝试的方式工作。我的错误是 在模板化我们的游泳池后不久,我没有意识到我可以 只需将它的静态实例放在我的分配器模板类中即可。 轰,问题解决了,现在所有的大小都是一致的。游泳池 现在工作正常,它现在是嵌入到 分配器模板类,它比我们的更精简和高效 以前的版本。~25 年的C++,模板从未停止让我惊叹。感谢您的帮助。

multiset

不直接存储Item,而是使用一些树结构来添加额外的指针来在树中导航。

它实际上使用TestAllocator<some_internal_node_type>来分配对象。这是您获得的节点类型的大小。

将显示函数修改为:

TestAllocator() { std::cout << "TestAllocator ctor: sizeof T:" << sizeof(T) << " ," << typeid(T).name() << std::endl; }

我得到输出:

Instantiating allocator:
TestAllocator ctor: sizeof T:20, 4Item
Instantiating container:
TestAllocator ctor: sizeof T:56, St13_Rb_tree_nodeI4ItemE

这应该可以消除您的困惑。 多集使用的模板类型是本身包含Item的节点类。 检查实现的 multiset 标头可能有助于查看分配器何时绑定和使用。