【问题标题】:C++ move semantics- what exactly is it to achieve? [duplicate]C++ 移动语义——它到底要实现什么? [复制]
【发布时间】:2013-05-24 09:21:08
【问题描述】:

这个“移动”语义的具体目的是什么?我知道如果您不通过引用传递副本,则副本由非原始类型组成,但是“移动”如何改变任何东西?为什么我们要“移动”数据?为什么不能把它保存在同一个地址而不是复制?如果发到别的地址,这不就是“复制删除”吗?

简而言之,我真的不明白移动语义究竟实现了什么。

【问题讨论】:

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


【解决方案1】:

移动语义结合了值传递和引用传递的优点。您静态分配类,因此您不必对它们的生命周期负责,并且可以将它们作为参数传递并轻松地从函数返回。另一方面,在通常对象被复制的情况下,它们被移动(仅复制它们的内部)。此操作的实现时间可能比复制要少得多(因为您知道,将不再使用 rhs 对象)。

MyObj * f()
{
    // Ok, but caller has to take care of
    // freeing the result
    return new MyObj();
}

MyObj f()
{
    // Assuming, that MyObj does not have move-ctor
    // This may be time-costly
    MyObj result;
    return result;
}

MyObj f()
{
    // This is both fast and safe
    MyObj result;
    return std::move(result);

    // Note, if MyObj implements a move-ctor,
    // usually you don't have to call std::move.
}

【讨论】:

    【解决方案2】:

    为什么不能保持在同一个地址而不是复制

    这实际上是移动语义通常所做的。它通常将资源(通常是内存,但可能是文件句柄等)保持在完全相同的状态,但它会更新对象中的引用。

    想象两个向量,srcdestsrc 向量包含一大块分配在堆上的数据,dest 是空的。当src 移动到dest 时,所有发生的事情是dest 被更新为指向堆上的内存块,而src 被更新为指向dest 指向的任何内容,在此案例,什么都没有。

    为什么这很有用?因为这意味着vector 可以在写入时确信只有一个向量会指向它分配的内存块。这意味着析构函数可以确保它清理已分配的内存。

    这可以扩展到管理其他资源的对象,例如文件句柄。现在可以编写可以拥有文件句柄的对象。这些对象可以是可移动的,但不可复制。因为 STL 容器支持可移动对象,所以它们可以比在 C++03 中更容易地放入容器中。它们的文件句柄或其他资源,保证只有对它的引用,并且析构函数可以适当地关闭它。

    【讨论】:

      【解决方案3】:

      我会用一个简单的向量代数例子来回答:

      class Vector{
        size_t dim_;
        double *data_;
      public:
        Vector(const Vector &arg)
          : dim_(arg.dim_)
          , data_(new double[dim_])
        {
          std::copy_n(arg.data_, dim_, data_);
        }
      
        Vector(Vector &&arg)
          : dim_(arg.dim_)
          , data_(arg.data_)
        {
          arg.data_ = nullptr;
        }
      
        ~Vector()
        {
          delete[] data_;
        }
      
        Vector& operator+= (const Vector &arg)
        {
          if (arg.dim_ != dim_) throw error;
          for (size_t idx = 0; idx < dim_; ++idx) data_[idx] += arg.data_[idx];
          return *this;
        }
      };
      
      Vector operator+ (Vector a, const Vector &b)
      {
        a += b;
        return a;
      }
      
      extern Vector v1, v2;
      
      int main()
      {
        Vector v(v1 + v2);
      }
      

      加法按值返回一个新向量。由于它是一个 r 值,它将被移动v,这意味着不会发生潜在巨大数组data_ 的额外副本。

      【讨论】:

        猜你喜欢
        • 2011-06-10
        • 2013-01-11
        • 1970-01-01
        • 1970-01-01
        • 2015-08-10
        • 2018-03-27
        • 1970-01-01
        • 2021-08-29
        相关资源
        最近更新 更多