2012-10-03 51 views
3

我有一個關於STL類和分配器的問題,似乎並不容易在線查​​找。有誰知道在嵌套的STL類中使用哪個分配器?例如:分配嵌套STL容器時使用哪個分配器?

typedef std::vector<int> myvect; 

//以下是編輯爲後續答覆中指出行/評論

typedef std::map<int, myvect, std::less<int>, A> mymap; //uses my custom allocator for map creation 

我們調用默認分配D,並假設我有一個自定義分配器A

,如果我做了以下會發生什麼:

  • 創建地圖:

    mymap mapInstance; 
    
  • 現在,假設項存在mapInstance[0],假設我推一個值向量:

    mapInstance[0].push_back(999); 
    

什麼分配器用於向量的動態內存mapInstance[0]

我的理解至今是默認分配D被使用,但我想確認自定義分配器A,被傳遞到地圖,不代替。 (據我所知,這隻會是發生我使用某種嵌套配置選項。)

我明白了,當然,對於mapInstance[0]元數據/頭信息使用自定義分配器分配A。我所關心的是動態內存部分,也就是d_dataBegin之後的部分。

+0

你應該知道的第一件事是,在標準庫,分配器改變容器(它的容器的模板參數)的類型,默認分配是無狀態的,因此*確切*分配器的副本在你的例子中使用它將不會有所作爲。 –

+0

是什麼'd_dataBegin'?在問題的最後一個字之前,這似乎沒有提到任何地方! –

回答

1

默認分配器D用於調用push_back

事實上,默認分配器也用於map,因爲容器的類型指定使用默認分配器。假設你的A繼承自std::allocator,所發生的一切就是你的分配器被切割成默認的分割器,並且容器的行爲就像你根本沒有傳遞分配器實例一樣。

+0

我沒有完全得到那個Mark--我編輯了我原來的問題,把分配器正確地傳遞給了地圖,但是我沒有得到你談論的部分A被切成默認的部分,並且容器的行爲像I根本沒有通過分配器實例。 假設分配器A內置了一些特殊的內存調試。如果我在原始問題中使用它來創建A,那麼你說的話是否適用(並且僅用於D?......我不完全同意,或者我錯過了某些內容)。 關於用於push_back調用的D,我同意。謝謝! –

+1

對於其他讀者的好處,當這個答案寫的問題使用'std :: map mapInstance(A)'所以馬克B是正確的,該地圖使用默認分配器 - 問題已編輯,所以這個答案看起來錯了現在雖然。 –

10

您的問題與Scoped Allocator Model有關,這是一種分配器設計風格,它自動將容器的分配器傳播到容器的元素,以便您可以確保從同一分配器分配所有容器的元素。更多關於下面的內容。

要回答你的問題:

1)集裝箱默認情況下不會使用範圍的分配模式,你必須明確地提出要求(見下文scoped_allocator_adaptor

2)你的嵌套容器類型std::vector<int>這意味着它使用默認的分配器std::allocator<int>,並且該類型的所有實例都是相同的,所以對於您的問題的答案是它使用標準分配器 - 哪一個並不重要,因爲每個std::allocator<int>都是相同的。


這個答案的其餘部分只是一個思想實驗中,回答你的問題是上面:vector<int>總是使用std::allocator<int>

現在,如果你嵌套類型爲std::vector<int, A1<int>>,其中A1<int>是自定義分配器的問題變得更有趣。

嵌套容器將使用它與構造的分配器,並且尚未顯示,因爲你說「假設一個條目存在mapInstance[0]」,並創建該條目如何纔是決定什麼分配器它會使用。

如果項創建這樣的:

mapInstance[0]; 

則該條目是缺省構造,並且將使用默認構造A1<int>

如果條目是這樣創建的:

A1<int> a1(/* args */); 
myvect v(a1) 
mapInstance.insert(mymap::value_type(0, v)); 

則該條目將是v副本,並在C++ 03的分配將是v.get_allocator()副本,但在C++ 11的分配器將是std::allocator_traits<A1<int>>::select_on_container_copy_construction(v.get_allocator())副本,這可能v.get_allocator()副本,但可能是不同的東西(例如,一個缺省構造A1)。它的創建後

(在C++中03項的分配不能改變,所以答案我uld在這裏結束,但在C++ 11中它可以被替換。我假設我們在這個問題的其餘部分正在討論C++ 11,因爲在C++ 03中分配器並不是很有趣。)

如果修改條目是這樣的:

A1<int> a1(/* args */); 
myvect v(a1) 
mapInstance[0] = v; 

那麼矢量被複制分配,這可能更換分配器,取決於std::allocator_traits<A1<int>>::propagate_on_container_copy_assignment::value

值。如果該條目是這樣修改的:

A1<int> a1(/* args */); 
mapInstance[0] = myvect(a1); 

然後向量被移動分配給,其中可能更換分配器,取決於std::allocator_traits<A1<int>>::propagate_on_container_move_assignment::value

值。如果該條目修改如下:

A1<int> a1(/* args */); 
myvect v(a1) 
swap(mapInstance[0], v); 

那麼矢量被交換,這可能更換分配器,取決於值的std::allocator_traits<A1<int>>::propagate_on_container_swap::value


現在,如果Astd::scoped_allocator_adaptor<A1<std::pair<const int, myvect>>>事情變得更加有趣!的scoped_allocator_adaptor是,正如其名稱所暗示的,一個適配器,它允許任何分配器類型將與作用域分配器模型這意味着容器的分配器可以被傳遞到容器的子使用,並且它的孩子的孩子,等等。(只要這些類型使用分配器,可以用它們來構建。)

默認情況下,容器和分配器也使用範圍的分配模式你需要使用scoped_allocator_adaptor(或寫你自己的分配器類型,其工作方式相同)來使用它。 (和C++ 03沒有支持在所有的作用域分配器。)

如果項創建這樣的:

mapInstance[0]; 

然後,而不是進入存在缺省構造的scoped_allocator_adaptor將建立其與地圖的分配器的一個副本,因此該條目將建造像myvect(A1<int>(mapInstance.get_allocator()))

如果該條目是這樣創建的:

A1<int> a1(/* args */); 
myvect v(a1) 
mapInstance.insert(mymap::value_type(0, v)); 

則該條目將有v的數據的副本,但不會使用它的分配,而是將被scoped_allocator_adaptor傳遞一個allocator,所以將建設這樣的:myvect(v, A1<int>(mapInstance.get_allocator()))


如果這一切都有點混亂,歡迎來到我的世界,但不用擔心,你的情況vector<int>總是使用std::allocator<int>