右值引用 – ‘移动构造函数’ 中的新特性在 C++98 中无法实现什么?

huangapple go评论51阅读模式
英文:

rvalue reference -what is new with 'move constructor' that could not have been implemented in C++98?

问题

以下是代码部分的中文翻译:

我是新手学习 C++ 11/17,试图理解右值引用移动(rvalue reference move)的工作原理。
在下面的代码中,“修改后的复制构造函数”和“移动构造函数”有什么区别?
我已经使它们完成了相同的任务,只是原型不同。如果我将“移动构造函数”注释掉,那么“修改后的复制构造函数”将仍然执行相同的操作。

我的观点是,为什么我们需要“移动构造函数”,它与我们旧版本的C++98有什么不同?我以前可以通过不同方式实现“复制构造函数”来完成相同的操作,并避免它过去执行的深复制。
我错过了什么?我不明白的是什么?

#include <iostream>

class A {
public:
    int* arr, size;
    bool flag;

    // 参数化构造函数
    A(int len) {
        size = len;
        arr = new int[size];
        flag = false;
    }

    // 修改后的复制构造函数
    A(A& temp) {
        arr = temp.arr;
        size = temp.size;
        flag = temp.flag;
        temp.arr = NULL;
    }

    // 移动构造函数
    A(A&& temp) {
        arr = temp.arr;
        size = temp.size;
        flag = temp.flag;
        temp.arr = NULL;

        std::cout << "A(A&& temp)" << std::endl;
    }

    // 析构函数
    ~A() {
        delete[] arr;
    }
};

A func()
{
    A obj(100000);
    return obj;
}

int main()
{
    A obj1 = func();
    std::cout << obj1.size << std::endl;
    return 0;
}
英文:

I am new at C++ 11/17 and trying to understand how the rvalue reference move works.
In the code below what is the difference between the "modified copy constructor" and "move constructor"?
I have made them to do the same thing but only a different prototype. If I make "move constructor" in a comment, well, the "modified copy constructor" will do just the same.

My point is why we need the "move constructor" how is it different now in C++17 from our old version of C++98? I just could do the same thing before only by implementing differently the "copy constructor" and avoid all the deep copy it used to do.
What am I missing? What I do not understand?

#include &lt;iostream&gt;

class A {
public:
    int* arr, size;
    bool flag;

    // parameterized constructor
    A(int len) {
        size = len;
        arr = new int[size];
        flag = false;
    }

    // modified copy constructor
    A(A&amp; temp) {
        arr = temp.arr;
        size = temp.size;
        flag = temp.flag;
        temp.arr = NULL;
    }

    // move constructor
    A(A&amp;&amp; temp) {
        arr = temp.arr;
        size = temp.size;
        flag = temp.flag;
        temp.arr = NULL;

        std::cout &lt;&lt; &quot; A(A&amp;&amp; temp)&quot; &lt;&lt; std::endl;
    }

    // destructor
    ~A() {
        delete[] arr;
    }
};

A func()
{
    A obj(100000);
    return obj;
}

int main()
{
    A obj1 = func();
    std::cout &lt;&lt; obj1.size &lt;&lt; std::endl;
    return 0;
}

I expected the move constructor add a new solution for a problem could not handle in c++98

答案1

得分: 5

一个对非常量对象的左值引用(即A&),例如在您的“修改”复制构造函数中使用的引用,不能绑定到右值(即临时对象),但对常量对象的左值引用(即const A&A const &)可以。

这就是为什么复制构造函数和复制赋值运算符通常接受常量引用。但是,这样做会阻止它们能够窃取对象的数据(复制本不应该这样做)。

func()返回一个临时对象,因此它返回一个右值。因此,A obj1 = func();(又名A obj(func());)在C++11之前不会编译,除非复制构造函数采用常量引用(应该如此)以便绑定到临时对象。

另一方面,右值引用(即A&&)可以绑定到右值(因此被命名为右值引用)。这是C++11中最重要的功能之一,允许实现移动语义。

因此,移动构造函数和移动赋值运算符可以从任何非常量对象中窃取数据,特别是从临时对象中,例如从函数的返回值中。而以前,它们只能从现有对象中窃取数据。

英文:

An lvalue reference to a non-const object (ie A&amp;), such as used in your "modified" copy constructor, cannot bind to an rvalue (ie a temporary object), but an lvalue reference to a const object (ie const A&amp; or A const &amp;) can.

This is why copy constructors and copy assignment operators typically take const references. But, doing so prevents them from being able to steal an object's data (which a copy shouldn't do anyway).

func() returns a temporary object, hence it returns an rvalue. As such, A obj1 = func(); (aka A obj(func());) does not compile pre-C++11 unless the copy constructor takes a const reference (as it should) in order to bind to the temporary object.

An rvalue reference (ie A&amp;&amp;), on the other hand, can bind to an rvalue (hence its name). This is the single most important feature added in C++11 that allows move semantics to be practical.

Thus, move constructors and move assignment operators can steal data from any non-const object, particularly a temporary object, such as from a function's return value. Whereas before, they could only steal data from a pre-existing object.

huangapple
  • 本文由 发表于 2023年2月8日 16:31:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/75383070.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定