C ++

对于push_backemplace_back之间的区别我有点困惑。

void emplace_back(Type&& _Val);
void push_back(const Type& _Val);
void push_back(Type&& _Val);

由于有一个push_back超载需要右值引用,我不太明白emplace_back的目的是什么?


除了什么访问者说:

由MSCV10提供的函数void emplace_back(Type&& _Val)是不符合和冗余的,因为正如你所说的那样,它严格地等同于push_back(Type&& _Val)

但真正的C ++ 0x形式的emplace_back真的很有用: void emplace_back(Args&&...) ;

它不采用value_type而是采用可变参数列表,这意味着您现在可以完美地转发参数并直接构造一个对象而不需要临时存储。

这很有用,因为无论有多聪明,RVO和移动语义带来的表格都还有复杂的情况,push_back可能会产生不必要的副本(或移动)。 例如,使用std::map的传统insert()函数,您必须创建一个临时文件,然后将其复制到std::pair<Key, Value> ,然后将其复制到映射中:

std::map<int, Complicated> m;
int anInt = 4;
double aDouble = 5.0;
std::string aString = "C++";

// cross your finger so that the optimizer is really good
m.insert(std::make_pair(4, Complicated(anInt, aDouble, aString))); 

// should be easier for the optimizer
m.emplace(4, anInt, aDouble, aString);

那么为什么他们没有在MSVC中实现正确版本的emplace_back呢? 事实上,前段时间它也给我带来了麻烦,所以我在Visual C ++博客上提出了同样的问题。 这里是Microsoft的Visual C ++标准库实现的官方维护者Stephan T Lavavej的回答。

问:现在beta2 emplace函数只是某种占位符吗?

答:你可能知道,可变参数模板在VC10中没有实现。 我们用诸如make_shared<T>() ,元组以及<functional>的新事物之类的预处理器机器来模拟它们。 这种预处理机器使用和维护相对困难。 另外,它会显着影响编译速度,因为我们必须重复包含子标题。 由于我们的时间限制和编译速度问题的结合,我们还没有模拟我们的emplace函数中的可变参数模板。

当可变参数模板在编译器中实现时,您可以期望我们将在库中使用它们,包括在我们的emplace函数中。 我们非常重视合规性,但不幸的是,我们无法立即做所有事情。

这是一个可以理解的决定。 每个试图用预处理器可怕的技巧来模拟可变模板的人都知道这些东西有多恶心。


emplace_back不应该接受vector::value_type类型的参数,而应该将可变参数转发给附加项目的构造函数。

template <class... Args> void emplace_back(Args&&... args); 

可以传递一个将被转发给拷贝构造函数的value_type

因为它转发参数,这意味着如果您没有右值,这仍然意味着容器将存储“复制”副本,而不是移动副本。

 std::vector<std::string> vec;
 vec.emplace_back(std::string("Hello")); // moves
 std::string s;
 vec.emplace_back(s); //copies

但是上面的内容应该和push_back相同。 它可能是用于像下面这样的用例:

 std::vector<std::pair<std::string, std::string> > vec;
 vec.emplace_back(std::string("Hello"), std::string("world")); 
 // should end up invoking this constructor:
 //template<class U, class V> pair(U&& x, V&& y);
 //without making any copies of the strings

下一个例子中可以演示emplace_back优化。

对于emplace_back构造函数将调用A (int x_arg) 。 对于push_back先调用A (int x_arg)再调用move A (A &&rhs)

当然,构造函数必须explicit标记,但是对于当前的示例来说,很好地消除显式性。

#include <iostream>
#include <vector>
class A
{
public:
  A (int x_arg) : x (x_arg) { std::cout << "A (x_arg)n"; }
  A () { x = 0; std::cout << "A ()n"; }
  A (const A &rhs) noexcept { x = rhs.x; std::cout << "A (A &)n"; }
  A (A &&rhs) noexcept { x = rhs.x; std::cout << "A (A &&)n"; }

private:
  int x;
};

int main ()
{
  {
    std::vector<A> a;
    std::cout << "call emplace_back:n";
    a.emplace_back (0);
  }
  {
    std::vector<A> a;
    std::cout << "call push_back:n";
    a.push_back (1);
  }
  return 0;
}

输出:

call emplace_back:
A (x_arg)

call push_back:
A (x_arg)
A (A &&)
链接地址: http://www.djcxy.com/p/73155.html

上一篇: c++

下一篇: Print Operator overload fail?