它是一个允许泛型容器类型(广义上的)检测泛型类型参数何时期望与分配器一起使用的协议。
然后,他们可以决定通过自动将外部分配器传播到内部类型来支持这一点。典型的例子是当你想要一个std::map<std::vector<std::string>, std::set<int> >
全部使用相同的分配器系列。
包含嵌套的类型allocator_type
typename 将自动被检测为uses_allocator
类型,包括所有标准容器。
典型其他uses_allocator
标准库中的类型有std::pair
and std::tuple
,还有函数包装类型(std::function
, std::packaged_type
)和容器适配器(std::stack
和朋友)。
作用域分配器允许调整外部分配器或外部分配器和一组内部分配器(如果它们不相同),从而通知作用域分配器感知容器要用于内部“使用分配器”类型的分配器类型。
来自 boost 文档scoped_allocator_adaptor
:
该类是 C++03 兼容的实现std::scoped_allocator_adaptor
。
类模板scoped_allocator_adaptor
是一个分配器模板,指定
容器(与任何其他容器一样)使用的内存资源(外部分配器)
allocator 执行)并且还指定要传递给的内部分配器资源
容器内每个元素的构造函数。
该适配器使用一个外部分配器和零个或多个内部分配器进行实例化
类型。如果仅使用一种分配器类型实例化,则内部分配器
成为scoped_allocator_adaptor
本身,因此使用相同的分配器
容器和容器内每个元素的资源,如果
元素本身是容器,它们的每个元素都是递归的。
如果使用多个分配器实例化,则第一个分配器是
外部分配器供容器使用,第二个分配器被传递给
容器元素的构造函数,以及元素本身
是容器,第三个分配器被传递给元素的元素,并且
很快。如果容器嵌套的深度大于容器的数量
分配器,最后一个分配器被重复使用,就像在单一分配器中一样
对于任何剩余的递归。
根据我的经验,Boost Container 始终比大多数标准库实现更好地支持该协议,但我承认我已经很多年没有检查过这些协议的状态了。
我刚刚为您提供了一个使用示例scoped_allocator_adaptor
在这个答案中:boost进程间是否支持在进程之间共享包含指针的对象? https://stackoverflow.com/questions/72310393/does-boost-interprocess-support-sharing-objects-containing-pointers-between-proc/72312694#72312694。在那张照片里,Shared::Bar
是内部“uses-allocator”类型的一个示例,它通知容器(vector
)在构造元素时传递其分配器的(转换后的)副本。
我在此处复制该答案的代码列表,以确保示例参考不会过时:
住在科里鲁 http://coliru.stacked-crooked.com/a/3dece79f14055b92
#include <boost/container/scoped_allocator.hpp>
#include <boost/container/string.hpp>
#include <boost/container/vector.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <string>
namespace bip = boost::interprocess;
namespace Shared {
#ifdef COLIRU
using Segment = bip::managed_mapped_file;
#else
using Segment = bip::managed_shared_memory;
#endif
using Mgr = Segment::segment_manager;
template <typename T>
using Alloc = boost::container::scoped_allocator_adaptor< //
bip::allocator<T, Mgr>>;
template <typename T> using Vector = std::vector<T, Alloc<T>>;
using String = boost::container::basic_string< //
char, std::char_traits<char>, Alloc<char>>;
struct Bar {
using allocator_type = Alloc<char>;
String first_name, last_name;
template <typename Alloc>
Bar(std::allocator_arg_t, Alloc alloc) : first_name(alloc)
, last_name(alloc) {}
template <typename Alloc>
Bar(Alloc&& alloc) : first_name(alloc)
, last_name(alloc) {}
Bar(Bar const&) = default;
template <typename Alloc>
Bar(Bar const& rhs, Alloc alloc) : first_name(rhs.first_name, alloc), last_name(rhs.last_name, alloc) {}
Bar& operator=(Bar const&) = default;
template <typename Alloc> Bar(std::string_view first_name, std::string_view last_name, Alloc alloc) :
first_name(first_name, alloc), last_name(last_name, alloc) {}
};
struct Snafu {
std::array<int, 5> no_problem;
};
struct Foo {
Vector<Bar> bars;
Vector<Snafu> snafus;
template <typename Alloc> //
Foo(Alloc alloc) : bars(alloc)
, snafus(alloc) {}
};
}
#include <iostream>
static inline std::ostream& operator<<(std::ostream& os, Shared::Foo const& foo) {
os << "Foo\n================\nBars:\n";
for (auto& [f, l] : foo.bars)
os << " - " << f << ", " << l << "\n";
os << "Snafus:";
for (auto& s : foo.snafus) {
os << "\n - ";
for (auto el : s.no_problem)
os << " " << el;
}
return os << "\n";
}
int main() { Shared::Segment msm(bip::open_or_create, "my_shared_mem", 10ull << 10);
Shared::Foo& foo = *msm.find_or_construct<Shared::Foo>("the_foo") //
(msm.get_segment_manager()); // constructor arguments
foo.bars.emplace_back("John", "Doe");
foo.bars.emplace_back("Jane", "Deer");
foo.bars.emplace_back("Igor", "Stravinsky");
foo.bars.emplace_back("Rimsky", "Korsakov");
foo.snafus.push_back({1, 2, 3});
foo.snafus.push_back({2, 3, 4});
foo.snafus.push_back({3, 4, 5, 6, 7});
std::cout << foo << "\n";
}