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

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

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

问题

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

  1. 我是新手学习 C++ 11/17,试图理解右值引用移动(rvalue reference move)的工作原理。
  2. 在下面的代码中,“修改后的复制构造函数”和“移动构造函数”有什么区别?
  3. 我已经使它们完成了相同的任务,只是原型不同。如果我将“移动构造函数”注释掉,那么“修改后的复制构造函数”将仍然执行相同的操作。
  4. 我的观点是,为什么我们需要“移动构造函数”,它与我们旧版本的C++98有什么不同?我以前可以通过不同方式实现“复制构造函数”来完成相同的操作,并避免它过去执行的深复制。
  5. 我错过了什么?我不明白的是什么?
  6. #include <iostream>
  7. class A {
  8. public:
  9. int* arr, size;
  10. bool flag;
  11. // 参数化构造函数
  12. A(int len) {
  13. size = len;
  14. arr = new int[size];
  15. flag = false;
  16. }
  17. // 修改后的复制构造函数
  18. A(A& temp) {
  19. arr = temp.arr;
  20. size = temp.size;
  21. flag = temp.flag;
  22. temp.arr = NULL;
  23. }
  24. // 移动构造函数
  25. A(A&& temp) {
  26. arr = temp.arr;
  27. size = temp.size;
  28. flag = temp.flag;
  29. temp.arr = NULL;
  30. std::cout << "A(A&& temp)" << std::endl;
  31. }
  32. // 析构函数
  33. ~A() {
  34. delete[] arr;
  35. }
  36. };
  37. A func()
  38. {
  39. A obj(100000);
  40. return obj;
  41. }
  42. int main()
  43. {
  44. A obj1 = func();
  45. std::cout << obj1.size << std::endl;
  46. return 0;
  47. }
英文:

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?

  1. #include &lt;iostream&gt;
  2. class A {
  3. public:
  4. int* arr, size;
  5. bool flag;
  6. // parameterized constructor
  7. A(int len) {
  8. size = len;
  9. arr = new int[size];
  10. flag = false;
  11. }
  12. // modified copy constructor
  13. A(A&amp; temp) {
  14. arr = temp.arr;
  15. size = temp.size;
  16. flag = temp.flag;
  17. temp.arr = NULL;
  18. }
  19. // move constructor
  20. A(A&amp;&amp; temp) {
  21. arr = temp.arr;
  22. size = temp.size;
  23. flag = temp.flag;
  24. temp.arr = NULL;
  25. std::cout &lt;&lt; &quot; A(A&amp;&amp; temp)&quot; &lt;&lt; std::endl;
  26. }
  27. // destructor
  28. ~A() {
  29. delete[] arr;
  30. }
  31. };
  32. A func()
  33. {
  34. A obj(100000);
  35. return obj;
  36. }
  37. int main()
  38. {
  39. A obj1 = func();
  40. std::cout &lt;&lt; obj1.size &lt;&lt; std::endl;
  41. return 0;
  42. }

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:

确定