C++ 向后推还是向后安放

C++ 向后推还是向后安放,c++,visual-studio-2010,stl,c++11,move-semantics,C++,Visual Studio 2010,Stl,C++11,Move Semantics,我对push_back和emplace_back之间的区别有点困惑 void emplace_back(Type&& _Val); void push_back(const Type& _Val); void push_back(Type&& _Val); 由于有一个使用右值引用的push\u-back重载,我不太明白emplace\u-back的目的是什么?emplace\u-back不应该使用类型为vector::value\u-type的参数,而应

我对
push_back
emplace_back
之间的区别有点困惑

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

由于有一个使用右值引用的
push\u-back
重载,我不太明白
emplace\u-back
的目的是什么?

emplace\u-back
不应该使用类型为
vector::value\u-type
的参数,而应该使用转发给附加项的构造函数的变量参数

template <class... Args> void emplace_back(Args&&... args); 
但是上面的内容应该与
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
std::向量向量向量机;
vec.emplace_back(std::string(“Hello”)、std::string(“world”);
//应最终调用此构造函数:
//模板对(U&&x、V&&y);
//不复制任何字符串

除了访客所说的以外:

MSCV10提供的功能
void emplace\u back(Type&&u Val)
是不一致的和冗余的,因为正如您所指出的,它严格等同于
push\u back(Type&&u Val)

但是真正的C++0x形式的
emplace_back
非常有用:

它不采用
value\u type
,而是采用可变参数列表,这意味着您现在可以完美地转发参数并直接将对象构造到容器中,而无需临时变量

这是很有用的,因为无论RVO和move semantic给表带来了多大的聪明,仍然存在一些复杂的情况,即push_back可能会产生不必要的拷贝(或移动)。例如,使用
std::map
的传统
insert()
函数,您必须创建一个临时文件,然后将其复制到
std::pair
,然后将其复制到映射中:

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);
std::map m;
int-anInt=4;
双倍=5.0;
std::string aString=“C++”;
//交叉手指,这样优化器就真的很好了
m、 插入件(标准:制作成对件(4件,复杂件(一件、一件、两件、一件));
//对优化器来说应该更容易
m、 侵位(4个,一个,一个,两个);
那么为什么他们没有在MSVC中实现正确版本的emplace_呢?事实上,前一阵子我也被它打扰了,所以我在网上问了同样的问题。下面是微软Visual C++标准库实现的官方维护者Stephan T Lavavej的解答。 问:beta 2安放功能现在只是某种占位符吗

你可能知道,可变模板 没有在VC10中实现。我们 用预处理器模拟它们 像这样的机器
make_shared()
、元组和新
中的内容。这 预处理器的机械相对简单 难以使用和维护。也, 它对编译有很大影响 速度,就像我们不得不重复的那样 包括分目。由于 结合我们的时间限制 考虑到编译速度的问题,我们 没有模拟可变模板 在我们的阵地上

当可变模板 在编译器中实现,您可以 预计我们将利用 他们在图书馆里,包括 我们的阵地功能。我们采取 我很认真,但是 不幸的是,我们不能做每件事 一下子


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

emplace\u back
一致性实现将参数添加到向量时转发给
vector::value\u type
构造函数。我记得Visual Studio不支持可变模板,但Visual Studio 2013 RC将支持可变模板,因此我猜将添加一致性签名

使用
emplace\u back
,如果您直接将参数转发给
vector::value\u type
构造函数,严格来说,
emplace\u back
函数不需要可移动或可复制的类型。在
vector
的情况下,这是没有用的,因为
vector::value_type
需要一个可复制或可移动的类型才能增长


但请注意,这对于
std::map
可能很有用,因为一旦在map中分配了条目,它就不再需要移动或复制,这与
vector
不同,这意味着您可以对既不可复制也不可移动的映射类型有效地使用
std::map

可在下一个示例中演示
emplace\u back
的优化

对于
emplace\u back
constructor
A(intx\u arg)
将被调用。以及
push_back
A(int x_arg)
首先调用,然后调用
move A(A&&rhs)

当然,构造函数必须标记为显式的,但对于当前示例,最好去掉显式性

#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;
}

列表的另一个示例:

// constructs the elements in place.                                                
emplace_back("element");

// creates a new object and then copies (or moves) that object.
push_back(ExplicitDataType{"element"});

这里显示了推回和安置推回的代码


您可以在push_back而不是emplace_back上看到移动操作。

emplace_back的特定用例:如果需要创建一个临时对象,然后将其推入容器中,请使用
emplace_back
而不是
push_back
。它将在容器内就地创建对象

注:

  • push_back
    在上述情况下,将创建一个临时对象并将其移动 放进容器里。然而,用于
    安置(u back
    的就地施工将更为有效 其性能优于构造然后移动对象(通常需要一些复制)
  • 通常,在所有情况下,您都可以使用
    emplace\u back
    而不是
    push\u back
    ,而不会产生太多问题。(见附件)

  • 这里有一些好的读物:注意(正如Thomas在下面所说的),问题中的代码来自MSVS对C++0x的模拟,而不是C++0x的实际情况。更好的读物是:。
    call emplace_back:
    A (x_arg)
    
    call push_back:
    A (x_arg)
    A (A &&)
    
    // constructs the elements in place.                                                
    emplace_back("element");
    
    // creates a new object and then copies (or moves) that object.
    push_back(ExplicitDataType{"element"});