为什么在临时销毁时你需要一个移动构造函数?

时间:2017-05-23 20:43:18

标签: c++

为什么在未命名对象只有活着直到完整表达式结束时才需要移动构造函数? 如果我们有这个代码:

class Example6 {
    string* ptr;
  public:
    Example6 (const string& str) : ptr(new string(str)) {}
    ~Example6 () {delete ptr;}
    // move constructor
    Example6 (Example6&& x) : ptr(x.ptr) {x.ptr=nullptr;}
    // move assignment
    Example6& operator= (Example6&& x) {
      delete ptr; 
      ptr = x.ptr;
      x.ptr=nullptr;
      return *this;
    }
};


int main () {

  Example6 bar = Example6("ple");   // move-construction

  return 0;
}

我们有一个Rvalue引用作为移动构造函数和赋值操作的参数。在这种情况下,bar的移动构造函数在初始化为同一个类的临时函数时被调用。我不明白的是:由于临时表具有完整表达式的生命周期,为什么需要移动构造函数而不是复制构造函数?我的意思是,隐式定义的移动构造函数和赋值运算符" erase"来自临时的数据,即使这些数据在分号后都会被销毁,那么为什么你需要一个移动构造函数,它与复制构造函数有些相同...为什么需要从临时数据中删除数据无论如何,在分号后被摧毁?

3 个答案:

答案 0 :(得分:1)

C ++添加移动构造函数主要是为了帮助提高性能。在不使用移动构造函数的情况下,可以进行适当的资源管理。实际上,这就是C ++在引入移动构造函数之前用来做的事情。

复制然后销毁临时文件的问题是被调用的复制构造函数不知道它被赋予临时复制权。因此,复制构造函数必须复制数据,就好像它的源不是临时的,可能在复制对象的过程中分配额外的资源。

当编译器知道你要复制一个临时文件时,它会让你知道你可以收获尽可能多的内部结构,这可能会节省你一些昂贵的分配。

答案 1 :(得分:0)

  

为什么需要从临时内容中删除数据   无论如何在分号后被摧毁?

不,这不是您想要移动构造函数的原因。

正如你所说,暂时的价值不重要因为它是暂时的,所以移动构造者可以“偷”"临时的数据,以避免昂贵的分配等。这是什么,它是什么给你提供更好的移动与复制性能,而不是因为数据将被删除。

移动是为了获得性能,而不是确保数据被删除"。

答案 2 :(得分:0)

原因如下:

  1. 复制elision是可选的,但允许在C ++ 17之前
  2. 你可以比临时移动更多。
  3. Rvalue引用为语言添加了许多新的可能性,因此它可以以更直观的方式工作,并且更有效。这方面的一个例子是unique_ptr。如果没有右值引用,您最终会得到scoped_ptr或auto_ptr。第一个是非常有限的使用,第二个是设计打破,因为它打破了最不惊讶的原则。
  4. 请注意,移动构造不会消除复制省略的需要。原始类型的移动与副本一样昂贵!