[英]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:我尝试了以下实验,看看我是否可以预测构造函数/操作符将如何被调用:
Now, I created a simple function that just returns an A object.现在,我创建了一个简单的 function,它只返回一个 A object。
A helper() {
return A(1);
}
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;
}
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 references
的value 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.