如何使用std :: scoped_allocator_adapter?

Kem*_*mal 8 c++ memory-management std allocator c++11

据我所知,std::scoped_allocator_adapter提供了一种控制机制,用于分别指定容器,元素,元素元素等使用哪个分配器,假设元素本身是容器.

也就是说,我无法理解语义std::scoped_allocator_adapter.

Bjarne Stroustrup在"C++编程语言 "第34.4.4节中提供了以下4个例子.1001(我将在我的问题中将它们称为示例-1,示例-2等.):

我们有四种方法来分配字符串向量:

// vector and string use their own (the default) allocator:
using svec0 = vector<string>;
svec0 v0;

// vector (only) uses My_alloc and string uses its own allocator (the default):
using Svec1 = vector<string,My_alloc<string>>;
Svec1 v1 {My_alloc<string>{my_arena1}};

// vector and string use My_alloc (as above):
using Xstring = basic_string<char,char_traits<char>, My_alloc<char>>;
using Svec2 = vector<Xstring,scoped_allocator_adaptor<My_alloc<Xstring>>>;
Svec2 v2 {scoped_allocator_adaptor<My_alloc<Xstring>>{my_arena1}};

// vector uses its own alloctor (the default) and string uses My_alloc:
using Xstring2 = basic_string<char, char_traits<char>, My_alloc<char>>;
using Svec3 = vector<xstring2,scoped_allocator_adaptor<My_alloc<xstring>,My_alloc<char>>>;
Svec3 v3 {scoped_allocator_adaptor<My_alloc<xstring2>,My_alloc<char>>{my_arena1}};
Run Code Online (Sandbox Code Playgroud)

为了完整起见,My_alloc书中定义如下:

template<typename T>
struct My_alloc { // use an Arena to allocate and deallocate bytes
    Arena& a;
    My_alloc(Arena& aa) : a(aa) { }
    My_alloc() {}
    // usual allocator stuff
};
Run Code Online (Sandbox Code Playgroud)

现在,关于我的问题:


问题1:在实施例-3,莫非元件Svec2使用My_alloc<char>{my_arena1},以用于(的类型及其元素分配存储char)?


问题2:如果是这样,它是否与在其定义中Xstring使用自定义分配器的事实有关My_alloc<char>?IOW,即使Xstring是用另一个分配器规定,不会对元素Svec_2 使用My_alloc<char>{my_arena1}以来scoped_allocator_adaptorSvec2_支配用于所做的分配,其分配Svec_2 分配由它的元素(类型做Xstring)?


问题3:考虑下面的代码,该代码应该是Example-3的变体.难道v2_(类型的元素std::string在这种情况下)使用My_alloc<char>{my_arena1}?如果没有,他们使用哪个分配器?

// both v2_ and its elements to use My_alloc<some_type>{my_arena1}
using Svec2_ = 
    vector<string, scoped_allocator_adaptor<My_alloc<string>>> // value_type std::string, instead of Xstring 
Svec2_ v2_ {scoped_allocator_adaptor<My_alloc<string>>{my_arena1}};
Run Code Online (Sandbox Code Playgroud)

问题4:基于对www.cppreference.com下面我引用的解释,在我看来,在例-4 ,Svec3没有使用其默认分配std::allocator给它的元素(的分配存储Xstring2类型),而是"外分配器",这是My_alloc<xstring>.元件Svec3,在另一方面,使用MyAlloc<char>这就是"内分配器".(而不是因为它是在定义中指定的分配Xstring2,而是因为它是"内部分配"中scoped_allocator_adapterSvec3.)

这就是它在www.cppreference.com std::scoped_allocator_adaptor节中所说的内容:

鉴于:

template< class OuterAlloc, class... InnerAlloc > class
    scoped_allocator_adaptor : public OuterAlloc;
Run Code Online (Sandbox Code Playgroud)

直接使用scoped_allocator_adaptor构造的容器 OuterAlloc用于分配其元素,但如果元素本身是容器,则它使用第一个内部分配器.所述元件该容器的,如果它们本身的容器中,使用第二内分配器等,如果有更多的水平到所述容器之外还有内分配器,所述最后内分配器再用于 所有进一步嵌套的容器.

基于此,不应该正确的例子如下?

// v3_ uses its default allocator(or rather std::allocator), while its elements use My_alloc
using Xstring2 = basic_string<char, char_traits<char>, My_alloc<char>>;
using Svec3_ = 
    vector<Xstring2, scoped_allocator_adaptor<std::allocator<Xstring2>, My_alloc<char>>>;
Svec3_ v3_ {
    scoped_allocator_adaptor<std::allocator<Xstring2>, My_alloc<char>>{my_arena1}
};
Run Code Online (Sandbox Code Playgroud)

这样一来,没有这个使用scoped_allocator_adaptor听写,通过分配Svec3_使用std::allocator,而它的元素使用My_alloc<char>{my_arena1}他们的分配?


我可以告诉我对scoped allocator模型有根本的误解.有人能指出我错过了什么吗?

Mit*_*iya 1

长话短说

问题 1
是的。

问题 2
不。

问题 3
否。使用
其默认分配器 (= )。std::allocator<char>()

问题 4
你是对的。
(但是示例 4 及其修改版本都无法编译,因为它们缺少外部分配器的构造函数参数。)

有人可以指出我缺少什么吗?
我不认为您误解了某些内容,而是您只是忘记了My_alloc不能用于std::string​​因为分配器类型std::stringstd::allocator,而不是My_alloc

请记住,分配器仅用于构造函数参数,因此不能使用具有不同类型的分配器。
正如 Jonathan Wakely 指出的那样,当Svec2orSvec2_创建它的元素时,它会调用:

std::allocator_traits<std::scoped_allocator_adaptor<My_alloc<xxx>>>::construct(
    get_allocator(), void_ptr, args...
);
Run Code Online (Sandbox Code Playgroud)

其中xxxXstring2forSvec2std::stringfor Svec2_
它调用get_allocator().construct(void_ptr, args...),然后调用以下任意一项:

std::allocator_traits<My_alloc<xxx>>::construct(
    outer_allocator(), void_ptr, std::allocator_tag, inner_allocator(), args...
);
Run Code Online (Sandbox Code Playgroud)

构造函数xxx(std::allocator_tag, inner_allocator(), args...)调用是否格式正确。

或者

std::allocator_traits<My_alloc<xxx>>::construct(
    outer_allocator(), void_ptr, args..., inner_allocator()
);
Run Code Online (Sandbox Code Playgroud)

构造函数xxx(args..., inner_allocator())调用是否格式正确。

或者

std::allocator_traits<My_alloc<xxx>>::construct(
    outer_allocator(), void_ptr, args...
);
Run Code Online (Sandbox Code Playgroud)

构造函数xxx(args...)调用是否格式正确。

在这些示例中, 和outer_allocator()inner_allocator()具有类型My_alloc<xxx>
所有std::basic_string分配器感知容器都具有构造函数,其最后一个参数是所有构造函数重载的分配器。
所以,如果inner_allocator()(类型My_alloc<xxx>) 可转换为元素的分配器类型,则调用第二种形式(即使用分配器);否则调用第三种形式(即从不使用分配器)。

对于Xstring2,分配器类型为My_alloc<char>,并且My_alloc<Xstring2>可转换为My_alloc<char>。因此, 的元素Svec2由 构造Xstring2(args..., inner_allocator()),然后它们的内部存储器由 分配My_alloc<char>
相比之下, 的分配器类型std::stringstd::allocator<char>, 并且My_alloc<Xstring2>不能转换为std::allocator<char>。因此, 的元素Svec2_由 构造std::string(args...),然后它们的内部内存由默认分配器 (= ) 分配std::allocator<char>()

FYI:严格来说,取决于std::uses_allocator是否使用第三种形式。