在一个类的内部同时实现常规拷贝构造函数和移动拷贝构造函数,常规赋值函数和移动赋值函数。
调用时若参数为一个左值,则调用常规函数;若参数为一个右值,则调用移动函数。
也可调用"std::move"强行调用移动函数。
#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()"时,析构栈空间的对象。析构顺序与构造顺序相反。 |
时间: 2024-11-14 10:07:49