c++ 11向量有了新函数emplace_back。与依赖编译器优化来避免复制的push_back不同,emplace_back使用完全转发将参数直接发送给构造函数以就地创建对象。在我看来,emplace_back做了所有push_back能做的事情,但有时它会做得更好(但不会更差)。

我使用push_back的原因是什么?


当前回答

考虑使用c++-17编译器的Visual Studio 2019会发生什么。我们在函数中有emplace_back,并设置了适当的参数。然后有人更改emplace_back调用的构造函数的参数。在VS中没有任何警告,代码编译也很好,然后在运行时崩溃。在此之后,我从代码库中删除了所有emplace_back。

其他回答

emplace_back的一些库实现行为不符合c++标准(包括Visual Studio 2012、2013和2015发布的版本)中指定的行为。

为了适应已知的编译器错误,如果参数引用迭代器或其他在调用后无效的对象,最好使用std::vector::push_back()。

std::vector<int> v;
v.emplace_back(123);
v.emplace_back(v[0]); // Produces incorrect results in some compilers

在一个编译器上,v包含值123和21,而不是预期的123和123。这是因为对emplace_back的第二次调用导致了大小的调整,此时v[0]无效。

上述代码的工作实现将使用push_back()而不是emplace_back(),如下所示:

std::vector<int> v;
v.emplace_back(123);
v.push_back(v[0]);

注意:使用int类型的vector仅用于演示目的。我在一个更复杂的类中发现了这个问题,这个类包括动态分配的成员变量,对emplace_back()的调用导致了硬崩溃。

push_back总是允许使用统一初始化,这是我非常喜欢的。例如:

struct aggregate {
    int foo;
    int bar;
};

std::vector<aggregate> v;
v.push_back({ 42, 121 });

另一方面,v.emplace_back({42,121});不会起作用。

考虑使用c++-17编译器的Visual Studio 2019会发生什么。我们在函数中有emplace_back,并设置了适当的参数。然后有人更改emplace_back调用的构造函数的参数。在VS中没有任何警告,代码编译也很好,然后在运行时崩溃。在此之后,我从代码库中删除了所有emplace_back。

向后兼容c++ 11之前的编译器。

仅对基本类型/内置类型或原始指针使用push_back。否则使用emplace_back。