Each resource type must have an RAII class to manage this resource. If you also have a smart pointer with deep copy semantics (quite easy to do), all you need to manage your resources in 99.9% of cases. I do not know why unique_ptr
does not make deep copies and does not raise the smart pointer, but if you have these two things, you do not need to write copy constructors, move constructors, assignment operators, move assignment operators and destructors. You may need to provide other constructors (including the default constructor), but there are five more places for errors.
#include <memory> template<class Type, class Del = std::default_delete<Type> > class deep_ptr : public std::unique_ptr<Type, Del> { public: typedef std::unique_ptr<Type, Del> base; typedef typename base::element_type element_type; typedef typename base::deleter_type deleter_type; typedef typename base::pointer pointer; deep_ptr() : base() {} //deep_ptr(std::nullptr_t p) : base(p) {} //GCC no has nullptr_t? explicit deep_ptr(pointer p) : base() {} deep_ptr(pointer p, const typename std::remove_reference<Del>::type &d) : base(p, d) {} //I faked this, it isn't quite right deep_ptr(pointer p, typename std::remove_reference<Del>::type&& d): base(p, d) {} deep_ptr(const deep_ptr& rhs) : base(new Type(*rhs)) {} template<class Type2, class Del2> deep_ptr(const deep_ptr<Type2, Del2>& rhs) : base(new Type(*rhs)) {} deep_ptr(deep_ptr&& rhs) : base(std::move(rhs)) {} template<class Type2, class Del2> deep_ptr(deep_ptr<Type2, Del2>&& rhs) : base(std::move(rhs)) {} deep_ptr& operator=(const deep_ptr& rhs) {base::reset(new Type(*rhs)); return *this;} template<class Type2, class Del2> deep_ptr& operator=(const deep_ptr<Type2, Del2>& rhs) {base::reset(new Type(*rhs)); return *this;} deep_ptr& operator=(deep_ptr&& rhs) {base::reset(rhs.release()); return *this;} template<class Type2, class Del2> deep_ptr& operator=(deep_ptr<Type2, Del2>&& rhs) {base::reset(rhs.release()); return *this;} void swap(deep_ptr& rhs) {base::swap(rhs.ptr);} friend void swap(deep_ptr& lhs, deep_ptr& rhs) {lhs.swap(rhs.ptr);} };
With this class (or one like that) you don't need to at all!
struct dog { deep_ptr<std::string> name; }; int main() { dog first; //default construct a dog first.name.reset(new std::string("Fred")); dog second(first); //copy construct a dog std::cout << *first.name << ' ' << *second.name << '\n'; second.name->at(3) = 'o'; std::cout << *first.name << ' ' << *second.name << '\n'; second = first; //assign a dog std::cout << *first.name << ' ' << *second.name << '\n'; }
As shown at http://ideone.com/Kdhj8
source share