举例说明

  1. #include <iostream>
  2. #include <cstring>
  3. using namespace std;
  4. class text
  5. {
  6. public:
  7. text() noexcept:
  8. _data(nullptr),_size(0)
  9. {
  10. cout << "default ctor" << endl;
  11. }
  12. ~text()
  13. {
  14. cout << "default dtor" << endl;
  15. _size = 0;
  16. if(_data!=nullptr)
  17. {
  18. free(_data);
  19. _data = nullptr;
  20. }
  21. }
  22. text(char* p) noexcept:
  23. _data(p),_size(strlen(p))
  24. {
  25. cout << "customized ctor" << endl;
  26. }
  27. text(const text& rhs)
  28. {
  29. _data = static_cast<char *>(malloc(rhs._size*sizeof(char)));
  30. _size = rhs._size;
  31. memcpy(this->_data, rhs._data, rhs._size);
  32. cout << "copy ctor" << endl;
  33. }
  34. text(text&& rhs) noexcept
  35. {
  36. _data = rhs._data;
  37. _size = rhs._size;
  38. rhs._data = nullptr;
  39. rhs._size = 0;
  40. cout << "move copy ctor" << endl;
  41. }
  42. text& operator=(const text& rhs)
  43. {
  44. if (this != &rhs) {
  45. _data = static_cast<char*>(malloc(rhs._size*sizeof(char)));
  46. memcpy(this->_data, rhs._data, rhs._size);
  47. cout << "assign ctor" << endl;
  48. }
  49. return *this;
  50. }
  51. text& operator=(text&& rhs) noexcept
  52. {
  53. if (this != &rhs) {
  54. _data = rhs._data;
  55. _size = rhs._size;
  56. rhs._data = nullptr;
  57. rhs._size = 0;
  58. cout << "move assign ctor" << endl;
  59. }
  60. return *this;
  61. }
  62. private:
  63. char* _data;
  64. int _size;
  65. };
  66. text factory()
  67. {
  68. char* str = (char*)malloc(strlen("hello world!") * sizeof(char));
  69. memcpy(str, "hello world!", strlen("hello world!"));
  70. text p(str);
  71. return p;
  72. }
  73. text factory_fast()
  74. {
  75. char* str = (char*)malloc(strlen("hello world!") * sizeof(char));
  76. memcpy(str, "hello world!", strlen("hello world!"));
  77. return text(str);
  78. }
  79. int main()
  80. {
  81. text cur = factory();
  82. return 0;
  83. }

未使用RVO优化输出

image.png

  1. 调用用户定义构造函数生成临时变量b
  2. 通过移动拷贝构造函数创建右值__tmp,用作返回值
  3. 变量b析构
  4. 调用移动拷贝构造函数创建cur
  5. 右值__tmp析构
  6. cur析构

    RVO优化结果1(包含临时变量创建)

    image.png

  7. 调用用户定义构造函数生成临时变量b

  8. 通过移动拷贝构造创建cur
  9. 变量b析构
  10. cur析构

编译器会将代码优化至如下伪代码:

  1. text factory_fast(const text &_result)
  2. {
  3. char* str = (char*)malloc(strlen("hello world!") * sizeof(char));
  4. memcpy(str, "hello world!", strlen("hello world!"));
  5. //重要
  6. text p;
  7. p.text::text(str); //customized ctor
  8. _result.text::text(str); //move copy ctor
  9. p.text::~text(); //default ctor
  10. return ;
  11. }

RVO优化结果2(factory_fast)

image.png
编译器会将代码优化至如下伪代码

  1. text factory_fast(const text &_result)
  2. {
  3. char* str = (char*)malloc(strlen("hello world!") * sizeof(char));
  4. memcpy(str, "hello world!", strlen("hello world!"));
  5. //重要
  6. _result.text::text(str); //customized ctor
  7. return ;
  8. }

总结

RVO的使用,减少了返回值__tmp的构造和析构的成本。若直接返回一个将亡值(此处为匿名对象),那么还会减少一次匿名对象的创建和析构!

NRVO

N代表name,于上述RVO的区别在于,其会将RVO的优化结果1中的结果,进一步优化成优化结果2中的结果。

编译器支持情况

VS在debug模式下支持RVO,在release模式下支持NRVO。