在C++中使用不同的分配器复制对象

Chr*_*odd 18 c++ c++11

所以我有一个很好的持久分配器类persistent_alloc<T>,它允许我在持久内存中分配C++容器对象和字符串,该内存由一个mmaped文件支持,该文件可以从我的程序的一次运行到下一次运行.

当我想做任何混合持久和非持久对象的事情时,我的问题就来了.例如,我有

typedef std::basic_string<char, std::char_traits<char>, persistent_alloc<char>> pstring;

pstring a, b, c;
std::string x, y, z;
Run Code Online (Sandbox Code Playgroud)

我希望能够做到这样的事情:

if (a == x)
    a = y;
c = z + b;
Run Code Online (Sandbox Code Playgroud)

等等,但默认情况下它不工作,作为pstringstd::string不相关类型.就比较而言,我可以定义:

template<typename Alloc1, typename Alloc2> inline bool
operator==(const std::basic_string<char, std::char_traits<char>, Alloc1> &a,
           const std::basic_string<char, std::char_traits<char>, Alloc2> &b)
{
    return strcmp(a.c_str(), b.c_str()) == 0;
}
Run Code Online (Sandbox Code Playgroud)

...现在我可以比较字符串的相等性.但是为每个操作添加这些操作似乎很痛苦 - 似乎它们应该由标准库提供.更糟糕的是,赋值运算符和复制构造函数必须是成员,不能像这样定义为全局内联函数.

这样做有合理的方法吗?或者我是否必须有效地重写整个标准库以有效地支持分配器?

Nic*_*las 8

有一种方法可以解决这个问题,但你需要在盒子外思考一下.你需要的是一个中间类型,它可以从std::string你的分配器字符串和你的分配器字符串中隐式构造.

目前在C++委员会面前这样建议.它基于Google已经存在的Apache许可实施.它被称为basic_string_ref; 它是一个模板类,它基本上是指向字符串中第一个字符的指针和一个表示字符串长度的大小.从某种意义上讲,它不是一个真正的容器,它不管理内存.

这正是你需要的.

basic_string_ref对于特定的字符类型,traits类型可以从一个std::basic_string 不管分配器隐式构造.

所有比较运算符都可以用来定义basic_string_ref.由于它可以从std::basic_string(并且几乎可以自由构造)隐式构造,因此它可以透明地用于不同分配的字符串之间的比较.

做任务相当棘手,但可行.它需要一系列转换:

a = pstring{basic_string_ref{y}};
Run Code Online (Sandbox Code Playgroud)

当然不是最漂亮的代码.我们宁愿简单地将复制构造函数和赋值运算符std::basic_string更改为分配器不可知.但由于这不可行,这真的是下一个最好的事情.你甚至可以将它包装在模板函数中:

template<typename DestAllocator, typename SourceAllocator, typename charT, typename traits>
std::basic_string<charT, traits, DestAllocator> conv_str(const std::basic_string<charT, traits, SourceAllocator> &input)
{
  return std::basic_string<charT, traits, DestAllocator>{basic_string_ref<charT, traits>{y}};
}
Run Code Online (Sandbox Code Playgroud)

当然,如果你能做到这一点,你可以这样做:

template<typename DestAllocator, typename SourceAllocator, typename charT, typename traits>
std::basic_string<charT, traits, DestAllocator> conv_str(const std::basic_string<charT, traits, SourceAllocator> &input)
{
  return std::basic_string<charT, traits, DestAllocator>{y.begin(), y.end()};
}
Run Code Online (Sandbox Code Playgroud)

如果这只是其中的一部分std::basic_string,那就太棒了,这样你就不需要解决方法了.但事实并非如此.