2017-10-28 169 views
3

在这段代码中,我得到一个不同的sizeof(T)如果分配器 是一个容器配置的一部分:为什么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在coliru.stacked-crooked.co对于所有选定的gcc编译器,对于所有选定的gcc编译器,20和56,0235,164,106,1745,,20和56对于3.8, 或20和48对于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的机会只传递项目的数量而不是字节。 正如你所看到的,它没有按照我尝试的方式工作。我的错误是在模板化我们的池后不久,我没有意识到我可以在我的分配器模板类中删除它的一个静态实例。 繁荣,问题解决了,现在所有sizeof的都是一致的。池 现在工作正常,它现在是嵌入到 分配器模板类中的模板,它比我们的 先前版本更加精简和高效。用C++约25年,模板永远不会让我惊叹。谢谢你的帮助。

回答

3

multiset不直接存储Item s,但使用某些树结构,添加额外的指针在树中导航。

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

+0

我想补充说这就是'rebind'成员模板的用途 - 容器使用它从'TestAllocator '类型到它实际使用的'TestAllocator 类型。 – aschepler

2

修改显示功能:

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 

应该打消你的困惑。 multiset使用的模板类型是一个节点类,它本身包含一个Item。检查实现的multiset头可能有助于查看分配器何时被绑定和使用。

相关问题