英文:
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 <iostream>
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& temp) {
arr = temp.arr;
size = temp.size;
flag = temp.flag;
temp.arr = NULL;
}
// move constructor
A(A&& temp) {
arr = temp.arr;
size = temp.size;
flag = temp.flag;
temp.arr = NULL;
std::cout << " A(A&& temp)" << std::endl;
}
// destructor
~A() {
delete[] arr;
}
};
A func()
{
A obj(100000);
return obj;
}
int main()
{
A obj1 = func();
std::cout << obj1.size << 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&
), 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&
or A const &
) 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&&
), 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论