C++ move semantics- what exactly is it to achieve?
这个"移动"语义的确切目的是什么?我理解如果你不通过引用传递一个副本是由非原语类型构成的,但是"移动"是如何改变任何东西的?为什么我们要"移动"数据?为什么不能把它放在同一个地址而不复制呢?如果它被发送到另一个地址,这不是一个"复制和删除"吗?
简言之,我真的不知道移动语义到底实现了什么。
移动语义结合了按值传递和按引用传递的优点。您可以静态地分配类,这样就不必为它们的生命周期负责,并且可以将它们作为参数传递并轻松地从函数返回。另一方面,在这种情况下,当通常复制对象时,它们会被移动(仅复制其内部)。此操作的实现时间可能比复制要短得多(因为您知道,不会再使用rhs对象)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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. } |
Why cant it just be kept at the same address and not copied
这实际上就是移动语义通常所做的。它通常将资源(通常是内存,但可能是文件句柄等)保持在完全相同的状态,但它会更新对象中的引用。
想象两个向量,
为什么这个有用?因为这意味着
这可以扩展到管理其他资源的对象,如文件句柄。现在可以编写可以拥有文件句柄的对象。这些对象可以移动,但不可复制。因为STL容器支持可移动对象,所以这些容器可以比C++ 03中的容器容易得多。它们的文件句柄或其他资源保证只有对它的引用,并且析构函数可以适当地关闭它。
我用向量代数的一个简单例子来回答:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 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值,所以它将被移到