std::scoped_allocator_adaptor 的目的是什么?
在 C++11 标准中,我们在动态内存管理库中有 std::scoped_allocator_adaptor
.这个类最重要的用例是什么?
In the C++11 standard we have std::scoped_allocator_adaptor
in the dynamic memory management library. What are the most important use cases of this class?
推荐答案
如果你想要一个字符串容器,并且想要对容器及其元素使用相同的分配器(因此它们都被分配在同一个区域中,如 TemplateRex描述)然后您可以手动执行此操作:
If you want a container of strings and want to use the same allocator for the container and its elements (so they are all allocated in the same arena, as TemplateRex describes) then you can do that manually:
template<typename T>
using Allocator = SomeFancyAllocator<T>;
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
using Vector = std::vector<String, Allocator<String>>;
Allocator<String> as( some_memory_resource );
Allocator<char> ac(as);
Vector v(as);
v.push_back( String("hello", ac) );
v.push_back( String("world", ac) );
但是,这很尴尬且容易出错,因为很容易意外插入不使用相同分配器的字符串:
However, this is awkward and error-prone, because it's too easy to accidentally insert a string which doesn't use the same allocator:
v.push_back( String("oops, not using same memory resource") );
std::scoped_allocator_adaptor
的目的是自动将分配器传播到它构造的对象如果它们支持使用分配器进行构造.所以上面的代码会变成:
The purpose of std::scoped_allocator_adaptor
is to automatically propagate an allocator to the objects it constructs if they support construction with an allocator. So the code above would become:
template<typename T>
using Allocator = SomeFancyAllocator<T>;
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
using Vector = std::vector<String, std::scoped_allocator_adaptor<Allocator<String>>>;
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
Allocator<String> as( some_memory_resource );
Allocator<char> ac(as);
Vector v(as);
v.push_back( String("hello") ); // no allocator argument needed!
v.push_back( String("world") ); // no allocator argument needed!
现在向量的分配器被自动用于构造它的元素,即使插入的对象 String("hello")
和 String("world")
,不是用相同的分配器构造的.由于 basic_string
可以从 const char*
隐式构造,最后两行可以进一步简化:
Now the vector's allocator is automatically used to construct its elements, even though the objects being inserted, String("hello")
and String("world")
, are not constructed with the same allocator. Since basic_string
can be implicitly constructed from const char*
the last two lines can be simplified even further:
v.push_back( "hello" );
v.push_back( "world" );
由于 scoped_allocator_adaptor
使用向量的分配器自动构造元素,这更加简单、易读且不易出错...
This is much simpler, easier to read, and less error-prone, thanks to scoped_allocator_adaptor
constructing the elements with the vector's allocator automatically..
当向量要求它的分配器构造一个元素作为 obj
的副本时,它调用:
When the vector asks its allocator to construct an element as a copy of obj
it calls:
std::allocator_traits<allocator_type>::construct( get_allocator(), void_ptr, obj );
通常分配器的 construct()
成员会调用类似:
Normally the allocator's construct()
member would then call something like:
::new (void_ptr) value_type(obj);
但是如果 allocator_type
是 scoped_allocator_adaptor
那么它使用模板元编程来检测 value_type
是否可以用适应型.如果 value_type
在其构造函数中不使用分配器,那么适配器会:
But if the allocator_type
is scoped_allocator_adaptor<A>
then it uses template metaprogramming to detect whether value_type
can be constructed with an allocator of the adapted type. If value_type
doesn't use allocators in its constructors then the adaptor does:
std::allocator_traits<outer_allocator_type>::construct(outer_allocator(), void_ptr, obj);
这将调用嵌套分配器的 construct()
成员,它使用类似placement new 的东西,如上所述.但是,如果对象确实支持在其构造函数中使用分配器,那么 scoped_allocator_adaptor::construct()
会:
And that will call the nested allocator's construct()
member, which uses something like placement new, as above. But if the object does support taking an allocator in its constructor then the scoped_allocator_adaptor<A>::construct()
does either:
std::allocator_traits<outer_allocator_type>::construct(outer_allocator(), void_ptr, obj, inner_allocator());
或:
std::allocator_traits<outer_allocator_type>::construct(outer_allocator(), void_ptr, std::allocator_arg, inner_allocator(), obj);
即适配器在其嵌套分配器上调用 construct()
时传递附加参数,以便使用分配器构造对象.inner_allocator_type
是 scoped_allocator_adaptor
的另一个特化,所以如果元素类型也是一个容器,它使用相同的协议来构造 its 元素,并且分配器可以传递给每个元素,即使你有容器容器等容器.
i.e. the adaptor passes additional arguments when it calls construct()
on its nested allocator, so that the object will be constructed with the allocator. The inner_allocator_type
is another specialization of scoped_allocator_adaptor
, so if the element type is also a container, it uses the same protocol to construct its elements, and the allocator can get passed down to every element, even when you have containers of containers of containers etc.
因此,适配器的目的是包装现有分配器并执行所有元编程和构造函数参数的操作,以将分配器从容器传播到其子级.
So the purpose of the adaptor is to wrap an existing allocator and perform all the metaprogramming and manipulation of constructor arguments to propagate allocators from a container to its children.
相关文章