C++ 为什么';std类型提供来自不同分配器的源的转换构造函数/赋值

C++ 为什么';std类型提供来自不同分配器的源的转换构造函数/赋值,c++,std,allocator,library-design,C++,Std,Allocator,Library Design,例如,为什么templatebasic_string{…}不提供: template< typename OtherAlloc > basic_string( const basic_string< Elem, Traits, OtherAlloc >& a_Other ) { ... } 模板 基本字符串(const basic字符串&a_Other){…} 实现这样一个同时考虑两个分配器的转换构造函数似乎相当简单。当前的情况使得在不同类型的分配器之间进行接

例如,为什么
templatebasic_string{…}
不提供:

template< typename OtherAlloc >
basic_string( const basic_string< Elem, Traits, OtherAlloc >& a_Other ) { ... }
模板
基本字符串(const basic字符串&a_Other){…}

实现这样一个同时考虑两个分配器的转换构造函数似乎相当简单。当前的情况使得在不同类型的分配器之间进行接口非常麻烦。

标准哈希也不允许分配器的乐趣-它可以哈希
std::string
std::wstring
,但不能
std::basic_string
。此外,您不能仅使用分配器创建
unordered\u映射
unordered\u集
——您还必须提供一个bucket number,它默认为您无法访问的实现定义的常量,因此您必须有效地补足一些内容。一般来说,支持不是很好


在我看来,相对简单地说,没有人提出这样的功能或探索这种使用空间。

这个问题比看起来要困难得多。由于分配器类型是对象类型的一部分,因此仅在分配器中不同的类型之间很少允许交互。想到的第一个例子是,通过常量引用接受
std::string
的函数不能接受使用不同分配器的字符串。一种特殊的情况是在构建对象的过程中。事实上,这里的情况可能更难

例如,考虑以下代码:

// Assume that you could construct from a different allocator
std::vector<int, allocator1> f() {
   std::vector<int, allocator2> r;
   // fill in
   return r;
}
int main() {
   std::vector<int, allocator3> x = f();
}
//假设您可以从不同的分配器构造
std::向量f(){
std::向量r;
//填补
返回r;
}
int main(){
std::向量x=f();
}
假设
allocator1
std::allocator
(即默认分配器),
allocator2
使用堆栈中的本地区域,
allocator3
可能使用共享内存。理论上,代码非常简单,向量
r
被创建并填充数据,在返回语句中,通过
r
复制来创建一个新的临时变量,最后通过从该临时变量复制来构建
x
。问题是该标准允许(以及类似的编译器)尽可能避免复制。在上面的特定示例中(忽略分配器),编译器将省略这两个副本并只创建一次缓冲区,这是快速高效的。但由于分配器可能不同,因此必须禁用NRVO和其他类型的复制省略。(如果这些优化被启用,
x
在main中将使用
allocator2
,本地竞技场已经被破坏,导致未定义的行为)

通过启用从具有一个分配器的容器到另一个分配器的复制构造,您可能会陷入混乱,或者陷入比当前标准更严重的混乱,在这种情况下,有状态分配器可能会引发各种有趣的问题(假设您使用每线程分配器,并且您将数据移动到共享队列中,您可能最终导致一个线程在另一个线程上持有由每线程分配器创建的对象,并且由于使用每线程分配器的目的是避免锁上的争用,因此您可能在显然安全的代码上创建争用条件……)



这是C++委员会的一个老建议,它提出了C++ 03分配模型的一些顾虑,并提出了一种多态分配器类型(它自身有问题)。它使阅读变得有趣,但要注意细节,不是所有的东西都看起来像它一样好,而且使用任一选项有很多缺陷。(或类似于C++03版本的C++11版本)

实现一个模板函数,在只在分配器中不同的std模板类型之间进行转换,可能不会太难。(我不是说这个问题无效——当然是——只是解决这个问题所需的代码量不应该太多。)是的,由于转换不能是免费的运算符,我必须在整个代码库中显式转换,但是,仍然可能是唯一的解决方案:(是的,很遗憾,自动转换是不可能的。我的自定义容器不支持不同的分配器,但那是因为我认为在使用具有不同
指针的容器时会发生冲突。我想不出这会阻碍什么,只要它们具有相同的
vvalue_type
。Yupp,在分配器不同的情况下没有NRVO。我知道当分配器不匹配时,任何类型的数据移动都是严格禁止的,但在我看来,由于最佳专门化规则,当分配器匹配时,利用最佳情况是相当容易的。@DavidRodríguez dribeas:好的,正如你所说,这样的构造函数不可能是复制构造函数,因为这毫无意义。然而,OP询问的是一个额外的转换构造函数,它不会有你提到的任何问题。最后一段中的问题适用于类似的代码,即使没有转换构造函数,所以我看不出它是如何工作的黎凡特。(这可能是相关的,但我看两遍后就看不出来了)@DavidRodríguez dribeas:我不知道你所说的容器不满足可交换要求是什么意思,因为分配器也被交换了,没有人建议能够与不同的分配器交换容器。所有这些都不能解释为什么我们不能有一个转换构造函数来简单地复制数据,即使allocator模型被破坏了。@Ylisar:BTW,有一个简单的解决方法:使用迭代器构造