简体   繁体   English

了解复制/移动构造函数和运算符之间的推理

[英]Understanding the reasoning between copy/move constructors and operators

I am trying to get the grasp of rvalue references and move semantics with a simple self-made example but I can't understand a specific part.我试图通过一个简单的自制示例来掌握右值引用并移动语义,但我无法理解特定部分。 I have created the following class:我创建了以下 class:

class A {
public:
    A(int a) {
        cout << "Def constructor" << endl;
    }

    A(const A& var) {
        cout << "Copy constructor" << endl;
    }

    A(A&& var) {
        cout << "Move constructor" << endl;
    }

    A& operator=(const A& var) {
        cout << "Copy Assignment" << endl;
        return *this;
    }

    A& operator=(A&& var) {
        cout << "Move Assignment" << endl;
        return *this;
    }
};

I tried the following experiments to see if I can predict how the constructors/operators are going to be called:我尝试了以下实验,看看我是否可以预测构造函数/操作符将如何被调用:

  1. A a1(1) - The default constructor is going to be called. A a1(1) - 将调用默认构造函数。 PREDICTED .预测
  2. A a2 = a1 - The copy constructor is going to be called. A a2 = a1 - 将调用复制构造函数。 PREDICTED .预测
  3. a1 = a2 - The copy assignment operator is going to be called. a1 = a2 - 将调用复制赋值运算符。 PREDICTED .预测

Now, I created a simple function that just returns an A object.现在,我创建了一个简单的 function,它只返回一个 A object。

A helper() {
   return A(1);
}
  1. A a3 = helper() - The default constructor is going to be called in order to create the object that the helper returns. A a3 = helper() - 将调用默认构造函数以创建助手返回的 object。 The move constructor is not going to be called due to RVO.由于 RVO,将不会调用移动构造函数。 PREDICTED .预测
  2. a3 = helper() - The default constructor is going to be called in order to create the object that the helper returns. a3 = helper() - 将调用默认构造函数以创建助手返回的 object。 Then, the move assignment operator is going to be called.然后,将调用移动赋值运算符。 PREDICTED .预测

Now comes the part I don't understand.现在是我不明白的部分。 I created another function that is completely pointless.我创建了另一个完全没有意义的 function。 It takes an A object by value and it just returns it.它需要一个 A object 的值,它只是返回它。

A helper_alt(A a) {
    return a;
}
  1. A a4 = helper_alt(a1) - This will call the copy constructor, to actually copy the object a1 in the function and then the move constructor. A a4 = helper_alt(a1) - 这将调用复制构造函数,以实际复制 function 中的 object a1,然后是移动构造函数。 PREDICTED .预测
  2. a4 = helper_alt(a1) - This will call the copy constructor, to actually copy the object a1 in the function and then I thought that the move assignment operator is going to be called BUT as I saw, first, the move constructor is called and then the move assignment operator is called. a4 = helper_alt(a1) - 这将调用复制构造函数,以实际复制 function 中的 object a1 然后我认为移动赋值运算符将被称为但是正如我所看到的,首先,调用移动构造函数并且然后调用移动赋值运算符。 HAVE NO IDEA .不知道

Please, if any of what I said is wrong or you feel I might have not understood something, feel free to correct me.拜托,如果我说的有任何错误,或者您觉得我可能没有理解某些内容,请随时纠正我。

My actual question : In the last case, why is the move constructor being called and then the move assignment operator, instead of just the move assignment operator?我的实际问题在最后一种情况下,为什么要调用移动构造函数,然后调用移动赋值运算符,而不仅仅是移动赋值运算符?

Congratulations, you found a core issue of C++!恭喜,你找到了 C++ 的一个核心问题!

There are still a lot of discussions around the behavior you see with your example code.关于您在示例代码中看到的行为仍有很多讨论。

There are suggestions like:有这样的建议:

A&& helper_alt(A a) {
    std::cout << ".." << std::endl;
    return std::move(a);
}

This will do what you want, simply use the move assignment but emits a warning from g++ "warning: reference to local variable 'a' returned", even if the variable goes immediately out of scope.这将满足您的需求,只需使用移动分配,但会从 g++ “警告:对返回的局部变量 'a' 的引用”发出警告,即使该变量立即脱离 scope。

Already other people found that problem and this is already made a c++ standard language core issue其他人已经发现了这个问题,这已经是c++ 标准语言核心问题

Interestingly the issue was already found in 2010 but not solved until now...有趣的是,这个问题在 2010 年就已经被发现,但直到现在才解决......

To give you an answer to your question " In the last case, why is the move constructor being called and then the move assignment operator, instead of just the move assignment operator? " is, that also C++ committee does not have an answer until now.为了回答您的问题“在最后一种情况下,为什么要调用移动构造函数,然后调用移动赋值运算符,而不仅仅是移动赋值运算符? ”也就是说,C++ 委员会直到现在还没有答案. To be precise, there is a proposed solution and this one is accepted but until now not part of the language.准确地说,有一个提议的解决方案,这个解决方案被接受,但直到现在还不是语言的一部分。

From: Comment Status来自: 评论状态

Amend paragraph 34 to explicitly exclude function parameters from copy elision.修改第 34 段,从复制省略中明确排除 function 参数。 Amend paragraph 35 to include function parameters as eligible for move-construction.修改第 35 段,将 function 参数包括为符合移动构造的条件。

consider the below example.考虑下面的例子。 I have compiled the sample code using -fno-elide-constructors flag to prevent RVO optimizations:我已经使用 -fno-elide-constructors 标志编译了示例代码以防止 RVO 优化:
g++ -fno-elide-constructors -o test test.cpp

#include<iostream>

using namespace std;

class A {
public:
    A(int a) {
        cout << "Def constructor" << endl;
    }

    A(const A& var) {
        cout << "Copy constructor" << endl;
    }

    A(A&& var) {
        cout << "Move constructor" << endl;
    }

    A& operator=(const A& var) {
        cout << "Copy Assignment" << endl;
        return *this;
    }

    A& operator=(A&& var) {
        cout << "Move Assignment" << endl;
        return *this;
    }
};

A a_global(1);

A helper_alt(A a) {
    return a;
}

A helper_a_local(A a) {
    A x(1);
    return x;
}

A helper_a_global(A a) {
    return a_global;
}

int main(){
    A a1(1);
    A a4(4);
    std::cout << "================= helper_alt(a1) ==================" << std::endl;
    a4 = helper_alt(a1);
    std::cout << "=============== helper_a_local()   ================" << std::endl;
    a4 = helper_a_local(a1);
    std::cout << "=============== helper_a_global()  ================" << std::endl;
    a4 = helper_a_global(a1);
    return 0;
}

This will result in the below output:这将导致以下 output:

Def constructor
Def constructor
Def constructor
================= helper_alt(a1) ==================
Copy constructor
Move constructor
Move Assignment
=============== helper_a_local()   ================
Copy constructor
Def constructor
Move constructor
Move Assignment
=============== helper_a_global()  ================
Copy constructor
Copy constructor
Move Assignment

As it can be seen, in simple words, C++ constructs a new temporary object ( rvalue ) when the return type is not a reference, which results in calling Move or Copy constructor depending on the value category of the returned object.可以看出,简单来说,C++在返回类型不是引用的情况下,构造了一个新的临时object( rvalue ),导致根据返回的ZA8CFDE6331BD49EB2AC916B666666666666666
Furthermore, it seems that all local variables of a function (including its arguments, which are passed by value) have a value category (eg, xvalue ) that can bind to rvalue references , which seems to be the case.此外,似乎 function 的所有局部变量(包括按值传递的 arguments)都有一个可以绑定到rvalue referencesvalue category (例如xvalue ),这似乎是这种情况。 I would be thankful to anyone who can provide a reference about the value category of a function argument (passed by value), inside the function.我将感谢任何可以在 function 内部提供有关 function 参数(按值传递)的value category的参考的人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 通过示例了解复制构造函数和赋值运算符 - Understanding copy constructors and assignment operators with an example C ++-组合复制/移动运算符和构造函数 - C++ - Combining Copy/Move operators and constructors 了解构造函数在移动、复制、分配语义中的行为 - Understanding the behavior of constructors in move, copy, assign semantics 删除基类中的复制和移动构造函数/赋值运算符就足够了吗? - Is deleting copy and move constructors/assignment operators in base class enough? 删除默认C ++复制和移动构造函数和赋值运算符的缺点? - Disadvantages to deleting default C++ copy and move constructors and assignment operators? 如何检查默认的复制/移动构造函数/赋值运算符? - How can I inspect the default copy/move constructors/assignment operators? 复制构造函数和赋值运算符 - Copy constructors and Assignment Operators 难以理解 C++ 构造函数和析构函数以及移动/复制语义 - Having trouble understanding C++ constructors and destructors and move/copy semantics C++ - 我的移动/复制构造函数和移动/复制赋值运算符有什么问题? - C++ - What is wrong with my move/copy constructors and move/copy assign operators? 理解虚拟副本构造函数 - understanding virtual copy constructors
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM