#include <algorithm>
#include <iostream>
template<class T>
struct default_delete {
void operator()(T* ptr) const {delete ptr;}
};
template<class T>
struct array_delete {
void operator()(T* ptr) const {delete [] ptr;}
};
template<class T, class D>
class unique_ptr;
template<class T, class D=default_delete<T> >
class move_unique_ptr {
//template<class U>
//friend move_unique_ptr<T, default_delete<T> > make_unique(const U& vs);
//friend move_unique_ptr<T, default_delete<T> > make_unique();
//friend move_unique_ptr<T, D> move(unique_ptr<T, D>& rhs);
friend class unique_ptr<T, D>;
typedef T* pointer;
D mutable dtor;
pointer mutable ptr;
move_unique_ptr& operator=(const move_unique_ptr& rhs);
public:
move_unique_ptr(T* rhs, D del) : dtor(del), ptr(rhs) {}
move_unique_ptr(const move_unique_ptr& rhs)
:dtor(rhs.dtor), ptr(rhs.ptr)
{ rhs.ptr = NULL; }
~move_unique_ptr() {dtor(ptr); ptr=NULL;}
};
template<class T, class D=default_delete<T> >
class unique_ptr : private D {
public:
unique_ptr() : D(), ptr(NULL) {}
unique_ptr(const move_unique_ptr<T, D>& rhs)
: D(rhs.dtor), ptr(rhs.ptr)
{rhs.ptr = NULL;}
~unique_ptr() {D::operator()(ptr);}
unique_ptr& operator=(move_unique_ptr<T, D>& rhs) {
unique_ptr t(rhs);
swap(t);
return *this;
}
void reset(T* ptr_=NULL) {
D::operator()(ptr);
ptr = ptr_;
};
T* get() const {return ptr;}
T* operator->() const {return ptr;}
T& operator*() const {return *ptr;}
D& get_deleter() {return *this;}
const D& get_deleter() const {return *this;}
operator void*() const {return ptr;}
T* release() {T* t = ptr; ptr = NULL; return t;} //you should almost never use this
void swap(unique_ptr& rhs) {
using std::swap;
swap(ptr, rhs.ptr);
swap(static_cast<D&>(*this), static_cast<D&>(*this));
}
void swap(move_unique_ptr<T, D>& rhs) {
swap(ptr, rhs.ptr);
swap(static_cast<D&>(*this), rhs.dtor);
}
private:
T* ptr;
unique_ptr(unique_ptr& rhs); //no impl
unique_ptr& operator=(unique_ptr& rhs); //no impl
};
template<class T, class D>
void swap(unique_ptr<T, D>& lhs, unique_ptr<T, D>& rhs)
{lhs.swap(rhs);}
template<class T, class U>
move_unique_ptr<T, default_delete<T> > make_unique(const U& v) //dont use auto
{return move_unique_ptr<T, default_delete<T> >(new T(v), default_delete<T>());}
template<class T>
move_unique_ptr<T, default_delete<T> > make_unique() //dont use auto
{return move_unique_ptr<T, default_delete<T> >(new T(), default_delete<T>());}
template<class T, class D>
move_unique_ptr<T, D> move(unique_ptr<T, D>& rhs)
{return move_unique_ptr<T, D>(rhs.release(), rhs.get_deleter());}
struct reporter {
reporter() {std::cout<<"default construct\n";}
reporter(const reporter&) {std::cout<<"copy construct\n";}
reporter& operator=(const reporter&) {std::cout<<"assignment\n";}
~reporter() {std::cout<<"destructor\n";}
};
move_unique_ptr<reporter> myfunc(unique_ptr<reporter> obj)
{
std::cout << "o="<<obj << '\n';
return move(obj);
}
int main() {
unique_ptr<reporter> a;
std::cout << "a="<<a << '\n';
unique_ptr<reporter> b = make_unique<reporter>();
std::cout << "b="<<b << '\n';
//unique_ptr<reporter > c = myfunc(b); //fails to compile
unique_ptr<reporter> c = myfunc(move(b));
std::cout << "b="<<b << '\n';
std::cout << "c="<<c << '\n';
a = myfunc(move(c));
std::cout << "a="<<a << '\n';
std::cout << "c="<<c << '\n';
//b = a; //fails to compile
b = move(a);
std::cout << "a="<<a << '\n';
std::cout << "b="<<b << '\n';
return 0;
}
/* output should be:
a=0x00000000
default construct
b=POINTER
o=POINTER
b=0x00000000
c=POINTER
o=POINTER
a=POINTER
c=0x00000000
a=0x00000000
b=POINTER
DESTRUCTOR
*/