#include #include #include using namespace std; // this class should have dynamic memory. class NoisyT { public: NoisyT (int n):name {n} { // code to do dynamic memory allocation. cout << "\t\tIn the constructor for item " << name << endl; } NoisyT (const NoisyT & other):name{other.name} { // code to do deep copy cout << "\t\tIn the copy constructor for item " << name << endl; } NoisyT & operator = (const NoisyT & other) { if (this == & other) { return *this; } // delete my stuff if necessary name = 0; // code to do deep copy name = other.name; cout << "\t\tIn the overloaded assignment operator of item " << name << endl; return *this; } NoisyT(NoisyT && other) noexcept { // code to do a shallow copy. name = other.name; // set the source to be null other.name = 0; cout << "\t\tIn the move constructor of item " << name << endl; } NoisyT & operator =(NoisyT && other) noexcept { if (this == & other) { return *this; } // delete my stuff if necessary name = 0; // code to do a shallow copy. name = other.name; // set the source to be null other.name = 0; cout << "\t\tIn the overloaded move assignment operator of item " << name << endl; return *this; } int GetName(void) const { return name; } private: int name; }; ostream & operator << (ostream & s, const NoisyT & n) { s << n.GetName(); return s; } NoisyT CreateNoisy() { cout << "\tIn CreateNoisy: return NoisyT(3);" << endl; return NoisyT(3); } int main() { // no supprise on these two. Constructor cout << endl; cout << "NoisyT a{1}; " << endl; NoisyT a{1}; cout << "\ta = " << a << endl; cout << "NoisyT c{2};" << endl; NoisyT c{2}; cout << "\tc = " << c << endl; cout << endl; // noting big here either, copy constructor. cout << "NoisyT b{a}; " << endl; cout << "\tBefore a = " << a << endl; NoisyT b{a}; cout << "\tAfter a = " << a << endl; cout << "\tAfter b = " << b << endl; cout << endl; // supprise, copy constructor, not copy constructor->assignment operator. cout << "NoisyT d = a;" << endl; cout << "\tBefore a = " << a << endl; NoisyT d = a; cout << "\tAfter a = " << a << endl; cout << "\tAfter d = " << d << endl; cout << endl; // this is the overloaded assignment operator. cout << "b = d;" << endl; cout << "\tBefore b = " << b << endl; cout << "\tBefore d = " << d << endl; b = d; cout << "\tAfter b = " << b << endl; cout << "\tAfter d = " << d << endl; cout << endl; // a little supprising. An object is constructed // the compiler detects that it is tempory // so the move assignment operator is called. cout << "c = CreateNoisy();" << endl; cout << "\tBefore c = " << c << endl; c = CreateNoisy(); cout << "\tAfter c = " << c << endl; cout << endl; vector data; // a standard copy constructor. cout << "data.push_back(c); " << endl; data.push_back(c); // but here, we need to double the size of the array, so // the copy constructor is called to copy the new item // and the move constructor is called to move the second item. cout << "data.push_back(d); " << endl; data.push_back(d); cout << endl; cout << "data.push_back(a); " << endl; data.push_back(a); cout << endl; cout << "data.pop_back(); " << endl; data.pop_back(); cout << "data.push_back(a); " << endl; data.push_back(a); cout << endl; // supprise, the compile does something completely different // See discussion of RVO (return value optimization) and NVRO on // page 303. cout << "NoisyT e{CreateNoisy()}; " << endl; NoisyT e{CreateNoisy()}; cout << "\tAfter e = " << e << endl; cout << endl ; cout <<"b = move(c);" << endl; cout << "\tBefore b = " << b << endl; cout << "\tBefore c = " << c << endl; b = move(c); cout << "\tAfter b = " << b << endl; cout << "\tAfter c = " << c << endl; cout << endl ; return 0; }