2017-10-28 216 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頭可能有助於查看分配器何時被綁定和使用。

相關問題