在C++11标准中,我们在动态内存管理库中有std::scoped_allocator_adaptor。这个类最重要的用例是什么?
发布于 2014-03-12 18:37:44
如果你想要一个字符串容器,并且想对容器和它的元素使用相同的分配器(就像TemplateRex描述的那样,它们都被分配在同一个竞技场中),那么你可以手动完成:
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) );但是,这很笨拙且容易出错,因为很容易意外插入不使用相同分配器的字符串:
v.push_back( String("oops, not using same memory resource") );std::scoped_allocator_adaptor的目的是自动将分配器传播到它构造的对象,如果这些对象支持使用分配器构造的话。因此,上面的代码将变成:
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")不是用相同的分配器构造的。由于可以从const char*隐式构造basic_string,因此可以进一步简化最后两行:
v.push_back( "hello" );
v.push_back( "world" );这更简单,更容易阅读,更不容易出错,这要归功于scoped_allocator_adaptor使用向量的分配器自动构造元素。
当向量请求其分配器构造一个元素作为obj的副本时,它调用:
std::allocator_traits<allocator_type>::construct( get_allocator(), void_ptr, obj );通常情况下,分配器的construct()成员会调用如下内容:
::new (void_ptr) value_type(obj);但是如果allocator_type是scoped_allocator_adaptor<A>,那么它将使用模板元编程来检测是否可以使用适应类型的分配器来构造value_type。如果value_type没有在其构造函数中使用分配器,那么适配器就会使用:
std::allocator_traits<outer_allocator_type>::construct(outer_allocator(), void_ptr, obj);这将调用嵌套分配器的construct()成员,该成员使用像上面这样的placement new。但是,如果对象支持在其构造函数中使用分配器,则scoped_allocator_adaptor<A>::construct()可以:
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的另一个特化,所以如果元素类型也是一个容器,它使用相同的协议来构造它的元素,并且分配器可以向下传递到每个元素,即使你有容器等等。
因此,适配器的目的是包装现有的分配器,并执行所有元编程和构造函数参数的操作,以将分配器从容器传播到其子容器。
https://stackoverflow.com/questions/22148258
复制相似问题