在C 11标准中,我们在动态内存管理库中有std :: scoped_allocator_adaptor.这个班级最重要的用例是什么?
解决方法:
如果你想要一个字符串容器,并希望对容器及其元素使用相同的分配器(因此它们都在同一个领域中分配,如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!
现在vector的allocator自动用于构造它的元素,即使插入的对象String(“hello”)和String(“world”)不是用相同的allocator构造的.由于basic_string可以从const char *隐式构造,因此最后两行可以进一步简化:
v.push_back( "hello" );
v.push_back( "world" );
由于scoped_allocator_adaptor自动使用向量的分配器构造元素,因此这更简单,更易于阅读,并且更不容易出错.
当向量要求其分配器构造一个元素作为obj的副本时,它调用:
std::allocator_traits<allocator_type>::construct( get_allocator(), void_ptr, obj );
通常,allocator的construct()成员会调用类似于:
::new (void_ptr) value_type(obj);
但是,如果allocator_type是scoped_allocator_adaptor< A>然后它使用模板元编程来检测value_type是否可以用自适应类型的分配器构造.如果value_type在其构造函数中不使用allocator,那么适配器会:
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的另一个特化,所以如果元素类型也是一个容器,它使用相同的协议来构造它的元素,并且分配器可以传递给每个元素,即使你有容器容器的容器等.
因此,适配器的目的是包装现有的分配器并执行构造函数参数的所有元编程和操作,以将分配器从容器传播到其子代.