I'd like to know do I need to write destructor in classes when I don't use raw pointers anymore? Just boost smart pointers.
In modern C++ programming, the Standard Library includes smart pointers, which are used to help ensure that programs are free of memory and resource leaks and are exception-safe.
C++ libraries provide implementations of smart pointers in following types: auto_ptr.
Smart pointers try to prevent memory leaks by making the resource deallocation automatic: when the pointer to an object (or the last in a series of pointers) is destroyed, for example because it goes out of scope, the pointed object is destroyed too.
In C++, a smart pointer is implemented as a template class that mimics, by means of operator overloading, the behaviors of a traditional (raw) pointer, (e.g. dereferencing, assignment) while providing additional memory management features.
Boost smart pointers by themselves don't have anything to do with the need for a destructor. All they do is remove the need for you to call delete on the allocated memory that they are effectively managing. So having said that, if before you started using smart pointers all you had in your destructors were calls to delete and delete[] freeing the memory of dynamically allocated class members and you have now switched all those regular pointers over to smart pointers, you could probably just switch to an empty destructor as they will now clean up for themselves when they go out of scope.
However, if for whatever reason, you have a class that needs to do cleanup (file cleanup, sockets, other resources etc) you will still need to provide a destructor to do that.
Let me know if that helps.
Each resource type should have a RAII class to manage that resource. If you also have a smart pointer with deep copy semantics (pretty easy to do), that's all you need to manage your resources 99.9% of the time. I don't know why unique_ptr
doesn't do deep copies, nor any boost smart pointer, but if you have those two things, you do not need to write copy constructors, move constructors, assignment operators, move assignment operators, nor destructors. You may or may not have to provide other constructors (including the default constructor), but that's five less places to make mistakes.
#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 similar), you don't need much 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 demonstrated at http://ideone.com/Kdhj8
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With