为什么 std 类型不提供来自分配器不同源的转换构造函数/赋值
Why doesn't std types provide conversion constructor / assignment from sources differing in allocator
例如,为什么template< typename Elem, typename Traits, typename Alloc > basic_string { ... }
不提供:
template< typename OtherAlloc >
basic_string( const basic_string< Elem, Traits, OtherAlloc >& a_Other ) { ... }
实现这样一个尊重两个分配器的转换构造函数似乎相当微不足道。当前的事务状态使得在分配器中不同的类型之间进行接口非常麻烦。
标准哈希也不允许分配器乐趣 - 它可以哈希std::string
和std::wstring
但不能std::basic_string<char, std::char_traits<char>, custom_alloc>
。此外,您不能仅使用分配器创建unordered_map
或unordered_set
- 您还必须提供一个存储桶编号,该编号默认为无法访问的实现定义的常量,因此您实际上必须编造一些东西。一般来说,支持不是很好。
在我看来,相对简单,没有人提出这样的功能或探索这个使用空间。
这个问题比看起来要困难得多。由于分配器类型是对象类型的一部分,因此仅在分配器中不同的类型之间允许很少进行交互。我想到的第一个示例是,通过常量引用获取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();
}
考虑到allocator1
是std::allocator<int>
的(即默认分配器),allocator2
使用堆栈中的本地竞技场,并且allocator3
可能使用共享内存。理论上,代码非常简单,向量r
被创建并填充数据,在 return 语句上,通过从 r
复制创建一个新的临时,最后通过从该临时复制来构造x
。问题在于该标准允许(和编译器喜欢)尽可能避免复制。在上面的特定示例中(并忽略分配器),编译器将省略两个副本并仅创建一次缓冲区,这既快速又高效。但是,由于分配器可能有所不同,因此必须禁用NRVO和其他类型的复制省略。(如果启用了这些优化,则 main 中的x
将使用 allocator2
,以及已被破坏的本地竞技场,从而导致未定义的行为)。
通过启用从一个分配器的容器到另一个分配器的复制构造,您最终可能会陷入混乱,或者比我们在当前标准中已经存在的更混乱,在这种情况下,您可以使用有状态分配器引起各种有趣的问题(假设您使用每线程分配器,并且将数据移动到共享队列中, 您最终可能会让一个线程在另一个线程上保存由每线程分配器创建的对象,并且由于使用每线程分配器的要点是避免对锁的争用,因此您可能会在看似安全的代码上创建争用条件。
这是向C++委员会提出的一个旧提案,旨在建立一个更好的分配模型,该模型提出了对C++03分配模型的一些担忧,并提出了一种多态分配器类型(它有自己的问题)。它读起来很有趣,但要注意细节,并非一切都像看起来那么好,使用任何一个选项(或类似于C++03版本的C++11版本)都存在很多陷阱。
- 为什么在使用转换构造函数赋值后调用C++类的析构函数?
- enable_if转换构造函数(静态强制转换,is_base_of)
- 为什么我需要在转换构造函数上引用 this->?
- 为什么在使用转换构造函数编译代码时需要 const 复制构造函数?
- 为什么不对转换构造函数进行隐式强制转换?
- 转换构造函数和运算符都存在且涉及显式性时的行为
- C++ 03 类模板 这是转换构造函数还是转换运算符?以及如何声明解决此问题的方法
- 使用完美转发的模板转换构造函数
- 转换构造函数的参数可以隐式转换吗?
- std::变量转换构造函数行为
- 隐式用户定义的转换不起作用,因为在编译C 时无法识别运算符和转换构造函数
- 为什么不调用模板类中的转换构造函数?
- 转换构造函数的隐式参数
- 转换构造函数:您如何解释C 中给定不同参数的函数
- C++变体:为什么转换构造函数需要大小.(类型)为非零
- C++变体用bool转换构造函数
- 在重载解析期间调用转换运算符,而不是在 c++17 中转换构造函数
- 为什么在没有赋值运算符的情况下调用转换构造函数
- 如何将转换构造函数与指针一起使用?
- 为什么在调用隐式类型转换构造函数之后直接是驱动器