// Write our own "smart pointer" // Using "R-value references" standardized since C++ 2011 #include using namespace std; template class smtptr { private: T *rawptr; // raw pointer public: smtptr(T* p) { rawptr = p; } smtptr() { rawptr = new T(); // assume T has such a contructor. } smtptr(T t) {// t is passed by copy, not by pointer // leaks t to heap, like in "Go" rawptr = new T(); *rawptr = move(t); } // overloading will distinguish between R and L-value reference /// all-important MOVE constructor (called when struct passed as arg) smtptr(smtptr&& arg) { // need to MOVE ownership from arg to this cout << "calling MOVE constructor op\n"; rawptr = arg.rawptr; arg.rawptr = NULL; }//move constructor /// move assignment operator smtptr& operator=(smtptr&& other) { //overload this=other cout << "calling MOVE assignment op\n"; delete(rawptr); // this is crucial! rawptr = other.rawptr; other.rawptr = NULL; }//copy-assignment operator // leaving these out forces call to move in order to compile... // this change was made to C++ compiler /* smtptr& operator=(const smtptr& other) { //overload this=other cout << "calling MOVE assignment op\n"; delete(rawptr); // this is crucial! rawptr = other.rawptr; other.rawptr = NULL; }//copy-assignment operator smtptr(const smtptr& arg) { // need to MOVE ownership from arg to this cout << "calling copy constructor op\n"; rawptr = arg.rawptr; arg.rawptr = NULL; }//copy constructor */ /// destructor ~smtptr() { if (rawptr) delete(rawptr); } /// overload *, -> operators to make this look like a real pointer T& operator *() { return *rawptr; } // *a=b must be possible (l-value ref) T* operator ->() { return rawptr; } // smtptr0-> (deref coerced to T*) T* operator &() { return rawptr; } // "deref coercion" operator bool() { return rawptr; } // for use in if(smtptr0)... T operator !() { return *rawptr; } // readonly dereference (like in F#) };// smtptr class smtptr g(smtptr x) //, smtptr& out) { smtptr sy(new int()); *sy = *x+10; return sy; } struct bst // simple binary tree structure { int item; // value stored at node smtptr left; smtptr right; bst(){} // default constructor required by template bst(int x) {item=x; } //leave constructo bst(int x, smtptr&& l, smtptr&& r) noexcept { item =x; left = move(l); right = move(r); } // aggregate constructor }; // mem-leak experiment (failed with std::unique_ptr) void doesitleak() { smtptr root(new bst(5)); root->right = smtptr(new bst(10)); } int main() { smtptr m; // calls smtptr() constructor *m = 1; smtptr n = move(m); /// won't compile without move! cout << *n << endl; if (m) cout << *m << endl; else cout << "m has moved!\n"; n = g(move(n)); cout << *n << endl; while (1) doesitleak(); return 0; }//main