分配嵌套的STL容器时使用哪个分配器?

Pra*_*ota 3 c++ stl vector map allocator

我有一个关于STL类和分配器的问题,这些问题似乎不容易在网上找到.有谁知道在嵌套的STL类中使用了哪个分配器?例如:

typedef std::vector<int> myvect;
Run Code Online (Sandbox Code Playgroud)

//按照后续回复/评论的指示编辑了以下行

typedef std::map<int, myvect, std::less<int>, A> mymap; //uses my custom allocator for map creation
Run Code Online (Sandbox Code Playgroud)

让我们调用默认的分配器D,并假设我有一个自定义分配器A.

如果我做了以下事情将会发生什么:

什么分配器用于向量的动态内存mapInstance[0]

到目前为止,我的理解D是使用了默认分配器,但我想确认A传入映射的自定义分配器不会被使用.(据我所知,只有我使用某种嵌套分配选项才会发生这种情况.)

当然,我理解mapInstance[0]使用自定义分配器分配元数据/标头信息A.我关心的是动态内存部分,即之后的部分d_dataBegin.

Jon*_*ely 11

你的问题与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];
Run Code Online (Sandbox Code Playgroud)

然后该条目是默认构造的,并将使用默认构造A1<int>.

如果该条目是这样创建的:

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

然后该条目将是vC++ 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中,条目的分配器在创建之后无法更改,因此答案将在此处结束,但在C++ 11中它可以被替换.我假设我们正在讨论C++ 11以解决此问题的其余部分,因为分配器在C++ 03中不是很有趣.)

如果该条目被修改如下:

A1<int> a1( /* args */ );
myvect v(a1)
mapInstance[0] = v;
Run Code Online (Sandbox Code Playgroud)

然后向量被复制分配给,可能会替换分配器,具体取决于值std::allocator_traits<A1<int>>::propagate_on_container_copy_assignment::value

如果该条目被修改如下:

A1<int> a1( /* args */ );
mapInstance[0] = myvect(a1);
Run Code Online (Sandbox Code Playgroud)

然后向量移动分配给,可能会取代分配器,具体取决于std::allocator_traits<A1<int>>::propagate_on_container_move_assignment::value

如果该条目被修改如下:

A1<int> a1( /* args */ );
myvect v(a1)
swap( mapInstance[0], v );
Run Code Online (Sandbox Code Playgroud)

然后交换向量,这可能会取代分配器,具体取决于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];
Run Code Online (Sandbox Code Playgroud)

然后,而不是默认构造的条目,scoped_allocator_adaptor将使用地图的分配器的副本构造它,因此条目将被构造为myvect( A1<int>(mapInstance.get_allocator()) ).

如果该条目是这样创建的:

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

然后该条目将有一个v数据的副本,但不会使用它的分配器,而是由它传递一个分配器scoped_allocator_adaptor,因此将构造如下:myvect( v, A1<int>(mapInstance.get_allocator()) ).


如果这有点令人困惑,欢迎来到我的世界,但不要担心,在你的情况下vector<int>永远使用std::allocator<int>.