本文共 7951 字,大约阅读时间需要 26 分钟。
在一个类的内部同时实现常规拷贝构造函数和移动拷贝构造函数,常规赋值函数和移动赋值函数。
调用时若参数为一个左值,则调用常规函数;若参数为一个右值,则调用移动函数。 也可调用"std::move"强行调用移动函数。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | #include <iostream> #include <utility> using std::cout; using std::endl; class Useless { private : int n; // number of elements char * pc; // pointer to data static int ct; // number of objects public : Useless(); explicit Useless( int k); Useless( int k, char ch); Useless( const Useless & f); // regular copy constructor Useless(Useless && f); // move constructor ~Useless(); Useless operator+( const Useless & f) const ; Useless & operator=( const Useless & f); // copy assignment Useless & operator=(Useless && f); // move assignment void ShowObject() const ; }; // implementation int Useless::ct = 0; Useless::Useless() { cout << "enter " << __func__ << "()\n" ; ++ct; n = 0; pc = nullptr; ShowObject(); cout << "leave " << __func__ << "()\n" ; } Useless::Useless( int k) : n(k) { cout << "enter " << __func__ << "(k)\n" ; ++ct; pc = new char [n]; ShowObject(); cout << "leave " << __func__ << "(k)\n" ; } Useless::Useless( int k, char ch) : n(k) { cout << "enter " << __func__ << "(k, ch)\n" ; ++ct; pc = new char [n]; for ( int i = 0; i < n; i++) pc[i] = ch; ShowObject(); cout << "leave " << __func__ << "(k, ch)\n" ; } Useless::Useless( const Useless & f): n(f.n) { cout << "enter " << __func__ << "(const &)\n" ; ++ct; pc = new char [n]; for ( int i = 0; i < n; i++) pc[i] = f.pc[i]; ShowObject(); cout << "leave " << __func__ << "(const &)\n" ; } Useless::Useless(Useless && f): n(f.n) { cout << "enter " << __func__ << "(&&)\n" ; ++ct; pc = f.pc; // steal address f.pc = nullptr; // give old object nothing in return f.n = 0; ShowObject(); f.ShowObject(); cout << "leave " << __func__ << "(&&)\n" ; } Useless::~Useless() { cout << "enter " << __func__ << "()\n" ; ShowObject(); --ct; delete [] pc; cout << "leave " << __func__ << "()\n" ; } Useless & Useless::operator=( const Useless & f) // copy assignment { cout << "enter " << __func__ << "(const &)\n" ; ShowObject(); f.ShowObject(); if ( this == &f) return * this ; delete [] pc; n = f.n; pc = new char [n]; for ( int i = 0; i < n; i++) pc[i] = f.pc[i]; ShowObject(); f.ShowObject(); cout << "leave " << __func__ << "(const &)\n" ; return * this ; } Useless & Useless::operator=(Useless && f) // move assignment { cout << "enter " << __func__ << "(&&)\n" ; ShowObject(); f.ShowObject(); if ( this == &f) return * this ; delete [] pc; n = f.n; pc = f.pc; f.n = 0; f.pc = nullptr; ShowObject(); f.ShowObject(); cout << "leave " << __func__ << "(&&)\n" ; return * this ; } Useless Useless::operator+( const Useless & f) const { cout << "enter " << __func__ << "(const &)\n" ; ShowObject(); f.ShowObject(); Useless temp = Useless(n + f.n); for ( int i = 0; i < n; i++) temp.pc[i] = pc[i]; for ( int i = n; i < temp.n; i++) temp.pc[i] = f.pc[i - n]; cout << "\t temp: " ; temp.ShowObject(); cout << "leave " << __func__ << "(const &)\n" ; return temp; } void Useless::ShowObject() const { cout << "\t this=" << this << ", ct=" << ct; cout << ", pc=(" << n << ", " << ( void *)pc << ", " ; if (n == 0) cout << "(object empty)" ; else for ( int i = 0; i < n; i++) cout << pc[i]; cout << endl; } // application int main() { Useless one(10, 'x' ); Useless two = one + one; // calls move constructor cout << "object one:\n" ; one.ShowObject(); cout << "object two:\n" ; two.ShowObject(); Useless three, four; cout << "three = one\n" ; three = one; // automatic copy assignment cout << "now object three:\n" ; three.ShowObject(); cout << "and object one:\n" ; one.ShowObject(); cout << "four = one + two\n" ; four = one + two; // automatic move assignment cout << "now object four:\n" ; four.ShowObject(); cout << "four = move(one)\n" ; four = std::move(one); // forced move assignment cout << "now object four:\n" ; four.ShowObject(); cout << "and object one:\n" ; one.ShowObject(); std::cin.get(); } |
测试结果如下。红色部分不是测试结果的一部分,是对测试结果的分析。
enter Useless(k, ch) this=0x7fffb5ade0f0, ct=1, pc=(10, 0x23f7010, xxxxxxxxxx leave Useless(k, ch) enter operator+(const &) this=0x7fffb5ade0f0, ct=1, pc=(10, 0x23f7010, xxxxxxxxxx this=0x7fffb5ade0f0, ct=1, pc=(10, 0x23f7010, xxxxxxxxxx enter Useless(k) this=0x7fffb5ade100, ct=2, pc=(20, 0x23f7030, leave Useless(k) temp: this=0x7fffb5ade100, ct=2, pc=(20, 0x23f7030, xxxxxxxxxxxxxxxxxxxx leave operator+(const &) object one: this=0x7fffb5ade0f0, ct=2, pc=(10, 0x23f7010, xxxxxxxxxx object two: this=0x7fffb5ade100, ct=2, pc=(20, 0x23f7030, xxxxxxxxxxxxxxxxxxxx //"Useless two = one +one;" //首先调用"operator+(const &)",在这个函数内调用"Useless(k)"生成temp对象。 //返回时调用拷贝构造函数生成一个临时匿名对象。 //析构temp对象。 //然后再调用移动拷贝构造函数,生成对象two。 //析构临时匿名对象。 //当前gcc版本是g++ (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4,对编译过程做了改进,直接把temp对象和two对象当成一个对象,省去了后面四步。 enter Useless() this=0x7fffb5ade110, ct=3, pc=(0, 0, (object empty) leave Useless() enter Useless() this=0x7fffb5ade120, ct=4, pc=(0, 0, (object empty) leave Useless() three = one enter operator=(const &) this=0x7fffb5ade110, ct=4, pc=(0, 0, (object empty) this=0x7fffb5ade0f0, ct=4, pc=(10, 0x23f7010, xxxxxxxxxx this=0x7fffb5ade110, ct=4, pc=(10, 0x23f7050, xxxxxxxxxx this=0x7fffb5ade0f0, ct=4, pc=(10, 0x23f7010, xxxxxxxxxx leave operator=(const &) now object three: this=0x7fffb5ade110, ct=4, pc=(10, 0x23f7050, xxxxxxxxxx and object one: this=0x7fffb5ade0f0, ct=4, pc=(10, 0x23f7010, xxxxxxxxxx four = one + two enter operator+(const &) this=0x7fffb5ade0f0, ct=4, pc=(10, 0x23f7010, xxxxxxxxxx this=0x7fffb5ade100, ct=4, pc=(20, 0x23f7030, xxxxxxxxxxxxxxxxxxxx enter Useless(k) this=0x7fffb5ade130, ct=5, pc=(30, 0x23f7070, leave Useless(k) temp: this=0x7fffb5ade130, ct=5, pc=(30, 0x23f7070, xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx leave operator+(const &)//"four = one + two"首先调用"operator+(const &)"函数。在这个函数内生成temp对象。 //在返回"operator+(const &)"函数后,并没有生成一个临时匿名对象,也没有析构temp对象,而是直接以temp做参数调用移动拷贝函数"operator=(&&)"。 enter operator=(&&) this=0x7fffb5ade120, ct=5, pc=(0, 0, (object empty) this=0x7fffb5ade130, ct=5, pc=(30, 0x23f7070, xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx this=0x7fffb5ade120, ct=5, pc=(30, 0x23f7070, xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx this=0x7fffb5ade130, ct=5, pc=(0, 0, (object empty) leave operator=(&&)//在返回"operator=(&&)"函数后才析构temp对象。 enter ~Useless() this=0x7fffb5ade130, ct=5, pc=(0, 0, (object empty) leave ~Useless() now object four: this=0x7fffb5ade120, ct=4, pc=(30, 0x23f7070, xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx four = move(one)//"four = std::move(one);"强行调用移动赋值函数"operator=(&&)"。 //调用之后,four对象接管了one对象的内部资源(pc和n),one对象没有被析构,但内部资源被“掏空”了! enter operator=(&&) this=0x7fffb5ade120, ct=4, pc=(30, 0x23f7070, xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx this=0x7fffb5ade0f0, ct=4, pc=(10, 0x23f7010, xxxxxxxxxx this=0x7fffb5ade120, ct=4, pc=(10, 0x23f7010, xxxxxxxxxx this=0x7fffb5ade0f0, ct=4, pc=(0, 0, (object empty) leave operator=(&&) now object four: this=0x7fffb5ade120, ct=4, pc=(10, 0x23f7010, xxxxxxxxxx and object one: this=0x7fffb5ade0f0, ct=4, pc=(0, 0, (object empty)//退出"main()"时,析构栈空间的对象。析构顺序与构造顺序相反。 enter ~Useless() this=0x7fffb5ade120, ct=4, pc=(10, 0x23f7010, xxxxxxxxxx leave ~Useless() enter ~Useless() this=0x7fffb5ade110, ct=3, pc=(10, 0x23f7050, xxxxxxxxxx leave ~Useless() enter ~Useless() this=0x7fffb5ade100, ct=2, pc=(20, 0x23f7030, xxxxxxxxxxxxxxxxxxxx leave ~Useless() enter ~Useless() this=0x7fffb5ade0f0, ct=1, pc=(0, 0, (object empty) leave ~Useless() |
本文转自FrankNie0101 51CTO博客,原文链接:http://blog.51cto.com/frankniefaquan/1934754,如需转载请自行联系原作者