c++11之右值引用和std::move

  • 这两个特性是c++11里比较有性能提升意义的。个人认为这两个特性也体现了c++对性能提升的极限追求。
  • 通过改写经典c++面试题mystring来体会
  • move不能减少临时变量的产生,但是可以减少内存的维护量
  • 代码
      1. //右值引用
      2. /*
      3. 左值对象:持久存在的对象,具有名字,可以对其去地址
      4. 右值对象:临时对象,表达式结束后它就没了,不能对它取地址,它也没有名字~
      5. 右值引用类型:引用右值的类型,用&&来表示
      6. */
      7. /************************************************************************/
      8. /*使用右值引用改进MyString类,添加移动构造函数 */
      9. /************************************************************************/
      10. #include<iostream>
      11. #include<vector>
      12. usingnamespace std;
      13. classMyString
      14. {
      15. public:
      16. //普通构造函数
      17. MyString()
      18. {
      19. cout <<"\n default construct\n";
      20. mLength =0;
      21. mData = NULL;
      22. }
      23. //带参数的普通构造函数
      24. MyString(constchar* str)
      25. {
      26. cout <<"\n arg construct\n";
      27. mLength = strlen(str);
      28. mData =newchar[mLength+1];
      29. memcpy(mData, str, mLength);
      30. mData[mLength]='\0';
      31. }
      32. //拷贝构造函数
      33. MyString(constMyString& str)
      34. {
      35. cout <<"\n copy construct\n";
      36. //深拷贝
      37. mLength = str.mLength;
      38. mData =newchar[mLength +1];
      39. memcpy(mData,str.mData,mLength);
      40. mData[mLength]='\0';
      41. }
      42. //移动构造函数
      43. MyString(MyString&& str)
      44. {
      45. cout <<"\n move construct\n";
      46. mLength = str.mLength;
      47. mData = str.mData;
      48. //
      49. str.mLength =0;
      50. str.mData = NULL;//这个是必须的,否则临时对象和此对象指向同一个资源,临时对象析构时会释放资源导致错误
      51. }
      52. //赋值函数
      53. MyString&operator=(constMyString& str)
      54. {
      55. cout <<"\n operator = \n";
      56. if(this!=&str)
      57. {
      58. if(mData)
      59. {
      60. delete[] mData;
      61. }
      62. mLength = str.mLength;
      63. mData =newchar[mLength +1];
      64. memcpy(mData, str.mData, mLength);
      65. mData[mLength]='\0';
      66. }
      67. return*this;
      68. }
      69. //右值赋值函数
      70. MyString&operator=(MyString&& str)
      71. {
      72. cout <<"\n right ref operator = \n";
      73. if(this!=&str)
      74. {
      75. if(mData)
      76. {
      77. delete[] mData;
      78. }
      79. mLength = str.mLength;
      80. mData = str.mData;
      81. str.mLength =0;
      82. str.mData = NULL;
      83. }
      84. return*this;
      85. }
      86. //析构函数
      87. ~MyString()
      88. {
      89. cout <<"\n destruct \n";
      90. if(mData)
      91. {
      92. delete[] mData;
      93. mData = NULL;
      94. }
      95. }
      96. public:
      97. size_t mLength;
      98. char* mData;
      99. };
      100. MyStringGetString()
      101. {
      102. MyString str("test str");
      103. return str;
      104. }
      105. int main()
      106. {
      107. int i =0;
      108. //i是左值,0是右值
      109. MyString a;
      110. MyString b("b");
      111. //这两个写法,对于编译器来说是一样的
      112. MyString c(b);
      113. MyString d = c;//这个只调用拷贝构造函数,不会调用赋值函数;分两行写就会调用赋值,为什么会这样。。。
      114. MyString e =GetString();
      115. MyString f(GetString());//调用移动构造函数
      116. MyString h;
      117. h =MyString();//调用右值赋值函数
      118. MyString g;
      119. g = e;//调用赋值函数
      120. MyString m;
      121. m =GetString();
      122. vector<MyString> v;
      123. MyString str("123");
      124. v.push_back(str);//会创建临时变量,调用拷贝构造函数
      125. v.push_back(std::move(str));//调用移动构造函数,std::move将左值引用转化为右值引用,
      126. //push_back在接受右值引用后调用类的移动构造函数将资源移动到
      127. //容器中,而右值引用对应的对象具体处理要参考具体移动构造函数的实现。我这里是将资源设null了。
      128. //移动语义的使用场合
      129. /************************************************************************/
      130. /* 目的,通过右值和资源移动来实现临时对象资源的所有权转移,减少内存操作(申请拷贝释放),对含有堆资源的对象才比较有意义,而且必须实现相应的移动构造函数 */
      131. /************************************************************************/
      132. }
       





posted on 2015-08-19 22:20  云东  阅读(2854)  评论(0编辑  收藏  举报