Problems with pointers:
1. Not initialized by constructors, so uninitialized pointers can be used (dangling pointer problem)
2. Not disposed of by destructors, so resources may not be deallocated (memory leak problem).
Solution: use of smart pointers, also called counted pointers. A smart pointer is a wrapper class for pointers. Since these are objects, they are initialized using constructors and their destructors are automatically called when go out of scope.
They also need to behave like ponters, so they need to overload the * and -> operators.
An example of such a wrapper class:
#ifndef SMARTPOINTER_H
#define SMARTPOINTER_H
template< typename Body >
/* Template requirements for Body:
* None
*/
class Handle {
public:
explicit Handle(Body* = 0);
Handle(const Handle&);
~Handle();
Handle& operator=(const Handle&);
Body* operator->();
Body& operator*();
private:
Body* bridge_;
int* counter_;
};
#endif
#include "smartpointer.h"
template< typename Body >
Handle< Body >::Handle(Body* b) : bridge_(b) {
counter_ = new int(1);
}
template< typename Body >
Handle< Body >::Handle(const Handle< Body >& h) : bridge_(h.bridge_) {
counter_ = h.counter_;
(*counter_)++;
}
template< typename Body >
Handle< Body >::~Handle< Body >() {
if(--counter_ == 0) {
delete counter_;
delete bridge_;
}
}
template
Handle< Body >& Handle< Body >::operator=(const Handle< Body >& rhs) {
if(this == &rhs || bridge_ == rhs.bridge_)
return *this;
if(--counter_ == 0) { // left-hand side has no references
delete counter_;
delete bridge_;
}
bridge_ = rhs.bridge_;
counter_ = rhs.counter_;
(*counter_)++;
return *this;
}
template< typename Body >
Body* Handle::operator->() {
return bridge_;
}
template< typename Body>
Body& Handle< Body >::operator*() {
return *bridge_;
}
Handle< Point > hp1(new Point(1, 2)); cout << hp1->getX() << endl; // hp1.operator->()->getX(); Handle< Point > hp2(hp1); // share points Handle< Point > hp3(new Point(3, 4)); hp3 = hp2; // deallocate point (3, 4) cout << hp2->getY() << " " << hp3->getY() << endl;