【问题标题】:why use a move constructor?为什么使用移动构造函数?
【发布时间】:2015-12-02 09:27:59
【问题描述】:

我有点困惑为什么你会使用/需要一个移动构造函数。
如果我有以下情况:

vector fill(istream& is)
{
    vector res;
    for(double x; is >> x; res.push_back(x));
    return res;
}

void bar()
{
    vector vec = fill(cin);
    // ... use vec ...
}

我可以通过添加 vector fill(istream& is, vector& res) 来消除返回 res 的需要,因此不调用复制构造函数。

那么有一个移动构造函数有什么意义呢?

【问题讨论】:

  • 你认为永远不需要在 C++ 中复制对象吗?如果是这样,那你就错了。
  • 一个原因是它更容易阅读。如果有函数调用somefunction(var1, var2, var3),不清楚其中一些是否被修改。
  • 您是否尝试过阅读有关移动构造函数和移动语义的一般主题?信息量很大,google一下就行了……
  • vector& res 添加到fill() 后,您需要在调用fill() 之前 构造一个vector。你真的认为这是一种进步吗?
  • @Ville-ValtteriTiittanen:那些没有被修改的参数应该是const,不是吗? ;-)(是的,我知道,他们经常不是。)

标签: c++ move-semantics move-constructor


【解决方案1】:

假设你接下来将std::vector<T> 放入std::vector<std::vector<T>>(如果你认为向量不应该嵌套,假设内部类型为std::string 并假设我们正在讨论std::string 的移动构造函数):即使您可以添加一个空对象并就地填充它,但最终矢量将需要在调整大小时重新定位,此时移动元素会派上用场。

请注意,从函数返回不是移动构造的主要动力,至少在效率方面不是这样:在效率很重要的情况下,构建代码以启用复制省略通过甚至避免移动来进一步提高性能。

不过,移动构造函数在语义上可能仍然相关,因为返回要求类型是可复制的或可移动的。某些类型(例如流)是不可复制的,但它们是可移动的并且可以通过这种方式返回。

【讨论】:

    【解决方案2】:

    在您的示例中,编译器可能会应用 RVO - 返回值优化,这意味着您的函数将被内联,因此不会发生返回 - 并且不会应用移动语义。仅当它不能应用 RVO - 将使用移动构造函数(如果可用)。

    在引入移动语义之前,人们使用各种技术来模拟它们。其中之一实际上是通过引用返回值。

    【讨论】:

      【解决方案3】:

      一个原因是使用赋值运算符可以更容易地掌握每一行的作用。如果有函数调用somefunction(var1, var2, var3),不清楚其中一些是否被修改。要找出这一点,您必须实际阅读其他函数。

      此外,如果您必须将向量作为参数传递给fill(),这意味着调用您的函数的每个地方都需要两行而不是一行:首先创建一个空向量,然后调用fill() .

      另一个原因是移动构造函数允许函数返回没有默认构造函数的类的实例。考虑以下示例:

      struct something{
          something(int i) : value(i) {}
          something(const something& a) : value(a.value) {}
      
          int value;
      };
      
      something function1(){
          return something(1);
      }
      
      void function2(something& other){
          other.value = 2;
      }
      
      int main(void){
          // valid usage
          something var1(18);
          // (do something with var1 and then re-use the variable)
          var1 = function1();
      
          // compile error
          something var2;
          function2(var2);
      }
      

      如果您担心效率,无论您是写fill() 以返回值还是将输出变量作为参数都无关紧要。您的编译器应将其优化为这两者中最有效的替代方案。如果你怀疑它没有,你最好测量一下。

      【讨论】:

      • 你不能“返回课程”。
      猜你喜欢
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-10
      相关资源
      最近更新 更多