我听说 Modern C ++ 的一个建议是使用emplace_back
代替push_back
来追加容器(emplace_back
接受任何版本的容器中存储类型的任何构造函数的参数。)
根据标准草案N3797 23.3.6.5(1),请说:
备注:如果新尺寸大于旧容量,则会导致重新分配。如果没有重新分配,插入点之前的所有迭代器和引用仍然有效。如果除了复制构造函数之外抛出异常,移动构造函数,赋值运算符或T的移动赋值运算符,或者通过任何InputIterator操作都没有效果。如果非CopyInsertable T的移动构造函数抛出异常,则效果未指定。
这指定了在不需要重新分配时会发生什么,但在容器需要增长时保持打开问题。
在这段代码中:
#include <iostream>
#include <vector>
int main() {
std::vector<unsigned char> buff {1, 2, 3, 4};
buff.emplace_back(buff[0]);
buff.push_back(buff[1]);
for (const auto& c : buff) {
std::cout << std::hex << static_cast<long>(c) << ", ";
}
std::cout << std::endl;
return 0;
}
在Windows 8.1中的 Debug 中使用 VC ++(Visual Studio 2013 Update 4)和 GCC 4.9.1(MinGW)进行编译。
使用VC ++编译时,输出为:
1, 2, 3, 4, dd, 2
使用GCC编译时,输出为:
1, 2, 3, 4, 1, 2
在VC ++中检查emplace_back
的实现,区别在于第一行代码,检查容器是否需要增长(如果需要则增长),在容器需要增长的情况下,对emplace_back
方法中收到的第一个元素( buff [0] )的引用无效,并且当容器的新创建元素中的值的实际设置发生时,该值无效
在push_back
工作的情况下,因为要在参数绑定中创建要追加的元素(在容器可能增长之前)。
我的问题是:
这种行为,当容器需要增长因为调用emplace_back
并且参数是对同一容器的引用时实现已定义,未指定或者其中一个编译器的实现存在问题(假设在VC ++中GCC行为更接近于预期的那些?
答案 0 :(得分:0)
当你使用&amp; operator []时,它返回了一个引用。然后使用emplace_back导致重新分配,从而使所有过去的引用无效。这两个规则都有明确的定义。应该发生的正确事是一个例外。我实际上希望VC ++版本在调试器下运行调试版本时抛出异常。
push_back具有相同的两个规则,这意味着它也将执行相同的操作。我几乎可以肯定,交换两行emplace_back / push_back会导致相同的行为。