i have small problem understanding why my smart pointer class is leaking on self assing.
If i do something like this
SmartPtr sp1(new CSine());//CSine is a class that implements IFunction iterface
sp1=sp1;
my colleagues told me that my smart pointer leaks. I added some log messages in my smart pointer to track what is going on and a test and reported this:
SmartPtr sp1(new CSine());
->CSine constructor
->RefCounter increment 0->1
->RefCounter constructor
->SmartPtr constructor
sp1=sp1;
->checks if this.RefCounter == to parameter.RefCounter, if true returns the smart pointer unmodified else modifies the object and returns it with the new values; in this case it returns true and returns the object unchanged.
at the end
->SmartPtr destructor
->RefCounter decrement 1->0
->RefCounter destructor
->CSine destructor
i can't understand why they consider that my smart pointer leaks...any ideas?
Thank you in advance!
class SmartPtr
{
private:
RefCounter* refCnt;
void Clear()
{
if(!isNull() && refCnt->Decr() == 0)
delete refCnt;
refCnt = 0;
};
public:
explicit SmartPtr();
explicit SmartPtr(IFunction *pt):refCnt(new RefCounter(pt)){};
SmartPtr(SmartPtr& other)
{
refCnt = other.refCnt;
if (!isNull())
refCnt->Incr();
};
virtual ~SmartPtr(void){Clear();};
SmartPtr& operator=(SmartPtr& other)
{
if(other.refCnt != refCnt)
{
if(!rVar.isNull())
other.refCnt->Incr();
Clear();
refCnt = other.refCnt;
}
return *this;
};
SmartPtr& operator=(IFunction* _p)
{
if(!isNull())
{
Clear();
}
refCnt = new RefCounter(fct);
return *this;
};
IFunction* operator->();
const IFunction* operator->() const;
IFunction& operator*();
const IFunction& operator*() const;
bool isNull() const { return refCnt == 0; };
inline bool operator==(const int _number) const;
inline bool operator!=(const int _number) const;
inline bool operator==(IFunction* _other) const;
inline bool operator!=(IFunction* _other) const;
inline bool operator==(SmartPtr& _other) const;
inline bool operator!=(SmartPtr& _other) const;
};
class RefCounter
{
friend class SmartPtr;
private:
IFunction* p;
unsigned c;
explicit RefCounter(IFunction* _p):c(0),p(_p)
{
if(_p != NULL)
Incr();
cout<<"RefCounter constructor."<<endl;
}
virtual ~RefCounter(void)
{
cout<<"RefCounter destructor."<<endl;
if(c == 0)
delete p;
}
unsigned Incr()
{
++c;
cout<<"RefCounter increment count:"<<c-1<<" to "<<c<<endl;
return c;
}
unsigned Decr()
{
if(c!=0)
{
--c;
cout<<"RefCounter decrement count:"<<c+1<<" to "<<c<<endl;
return c;
}
else
return 0;
}
};
SmartPtr& operator=(SmartPtr& other)
{
if(rVar.refCnt != refCnt)
should be:
if ( this != & other )
You might want to look at the following quote from A Proposal to Add General Purpose Smart Pointers to the Library Technical Report:
The Boost developers found a shared-ownership smart pointer exceedingly difficult to implement correctly. Others have made the same observation. For example, Scott Meyers [Meyers01] says:
"The STL itself contains no reference-counting smart pointer, and writing a good one - one that works correctly all the time - is tricky enough that you don't want to do it unless you have to. I published the code for a reference-counting smart pointer in More Effective C++ in 1996, and despite basing it on established smart pointer implementations and submitting it to extensive pre- publication reviewing by experienced developers, a small parade of valid bug reports has trickled in for years. The number of subtle ways in which reference-counting smart pointers can fail is remarkable."
If this is homework, read about how to implement copy ctor and assignment operator using a swap() (member) function. Otherwise, do not try to write your own smart pointer. You cannot win.
I don't see a leak either, but I think there are some other problems (other than many compiler errors - this cannot be the code you are using):
SmartPtr& operator=(SmartPtr& other)
should take the argument by const reference. You don't have to increment the reference count of other, because you can do it on the non-const left-hand side, as they will be sharing the same reference count instance.
Next, the canonical way to implement assignment for such classes is using the copy-and-swap idiom - which means you should also define a trivial swap method (which just swaps the pointers), and worry less about self-assignment :)
My impression is that there is no memory leak.
To be sure:
test with valgrind or the VS-alternative
use std::tr1::shared_ptr (if this is more than educational)
Your code doesn't compile, which leads me to believe that the version you posted can't be the version you colleagues are complaining about.
Pretty much any smart pointer will have cases where it leaks. It's just the way that it has to be if you implement it using references. There's also a million other problems plus they are slow. Since they are buggier than raw pointers there's really not much use if all you get out of it is reference counting. I have been tempted to use them for some very special purposes but they are not for general programming use. There's a reason that they are not allowed in STL containers for example.
Related
Why isn't the observer_ptr zeroed after a move operation?
It is correctly set to nullptr in its default construction, and that does make sense (and prevents pointing to garbage).
And, accordingly, it should be zeroed when std::move()'d from, just like std::string, std::vector, etc.
This would make it a good candidate in several contexts where raw pointers make sense, as well as automatic generation of move operations on classes with raw pointer data members, like in this case.
EDIT
As #JonathanWakely pointed out in the comments (and that is related to the aforementioned question):
if observer_ptr was null after a move it can be used to implement
the Rule of Zero for types that have a pointer member. It's a very
useful feature.
It seems like many people miss the point and the utility of this idea at first.
Consider:
template<typename Mutex>
class unique_lock
{
Mutex* pm;
public:
unique_lock() : pm() { }
unique_lock(Mutex& m) : pm(&m) { }
~unique_lock() { if (pm) pm->unlock(); }
unique_lock(unique_lock&& ul) : pm(ul.pm) { ul.pm = nullptr; }
unique_lock& operator=(unique_lock&& ul)
{
unique_lock(std::move(ul)).swap(*this);
return *this;
}
void swap(unique_lock& ul) { std::swap(pm, ul.pm); }
};
With a "dumb" smart pointer that is null-on-default-construction and null-after-move you can default three of the special member functions, so it becomes:
template<typename Mutex>
class unique_lock
{
tidy_ptr<Mutex> pm;
public:
unique_lock() = default; // 1
unique_lock(Mutex& m) : pm(&m) { }
~unique_lock() { if (pm) pm->unlock(); }
unique_lock(unique_lock&& ul) = default; // 2
unique_lock& operator=(unique_lock&& ul) = default; // 3
void swap(unique_lock& ul) { std::swap(pm, ul.pm); }
};
That's why it's useful to have a dumb, non-owning smart pointer that is null-after-move, like tidy_ptr
But observer_ptr is only null-on-default-construction, so if it is standardized it will be useful for declaring a function to take a non-owning pointer, but it won't be useful for classes like the one above, so I'll still need another non-owning dumb pointer type. Having two non-owning dumb smart pointer types seems almost worse than having none!
So, move constructors are designed to make copy constructors cheaper in certain cases.
Let's write out what we'd expect these constructors and destructors to be: (This is a bit of a simplification, but that's fine for this example).
observer_ptr() {
this->ptr == nullptr;
}
observer_ptr(T *obj) {
this->ptr = obj;
}
observer_ptr(observer_ptr<T> const & obj) {
this->ptr = obj.ptr;
}
~observer_ptr() {
}
You're suggesting that the class provides a move constructor that looks like:
observer_ptr(observer_ptr<T> && obj) {
this->ptr = obj.ptr;
obj.ptr = null;
}
When I would suggest that the existing copy constructor will work fine as is, and is cheaper than the suggested move constructor.
What about std::vector though?
A std::vector, when copied, actually copies the array that it backs. So, a std::vector copy constructor looks something like:
vector(vector<T> const & obj) {
for (auto const & elem : obj)
this->push_back(elem);
}
The move constructor for the std::vector can optimize this. It can do this because that memory can be stolen from obj. In a std::vector, this is actually useful to do.
vector(vector<T> && obj) {
this->data_ptr = obj.data_ptr;
obj.data_ptr = nullptr;
obj.size = 0;
}
Aside from the minor performance impact of zeroing the moved-from observer_ptr, which is easily worked around (copy instead of move), the main rationale was probably to mimic the behaviour of regular pointers as closely as possible, following the principle of least surprise.
However, there is a potentially far more significant performance issue: defaulting the move functions allows an observer_ptr to be trivially copyable. Trivial copyability allows an object to be copied using std::memcpy. If observer_ptr were not trivially copyable, neither would any classes with an observer_ptr data member, resulting in a performance penalty that cascades down the compositional class hierarchy.
I have no idea what kind of performance improvements can be gained by using the std::memcpy optimization, but they're probably more significant than the aforementioned minor performance issue.
As mentioned here you can use reference (d-reference) instead of pointer (d-pointer) in case of PIMPL idiom.
I'm trying to understand if there are any serious issues with this implementation and what are the pros and cons.
Pros:
Shorter syntax because of usage of "." instead of "->".
...
Cons:
What if the new ObjectPivate() fails and new doesn't throw (e.g.: new(std::nothrow) or custom new) and returns nullptr instead? You need to implement additional stuff to check if the referance is valid. In case of pointer you just use:
if (m_Private)
m_Private->Foo();
In rare case of multiple constructors for the Object with complex initialisation logic the solution could be not applicable. [© JamesKanze]
It fills more natural to use pointer for memory management. [© JamesKanze]
Some additional implementation details needs to be considered (use of swap()) to ensure the exception-safety (e.g. implementation of assignment operator) [© Matt Yang]
...
Here the sample code for illustration:
// Header file
class ObjectPrivate;
class Object
{
public:
Object();
virtual ~Object();
virtual void Foo();
private:
ObjectPrivate& m_Private;
};
// Cpp file
class ObjectPrivate
{
public:
void Boo() { std::cout << "boo" << std::endl; }
};
Object::Object() :
m_Private(* new ObjectPrivate())
{
}
Object::~Object()
{
delete &m_Private;
}
void Object::Foo()
{
m_Private.Boo();
}
It's really just a matter of style. I tend to not use
references in classes to begin with, so using a pointer in the
compilation firewall just seems more natural. But there's
usually no real advantage one way or the other: the new can
only fail by means of an exception.
The one case where you might favor the pointer is when the
object has a lot of different constructors, some of which need
preliminary calculations before calling the new. In this
case, you can initialize the pointer with NULL, and then call
a common initialization routine. I think such cases are rare,
however. (I've encountered it once, that I can recall.)
EDIT:
Just another style consideration: a lot of people don't like something like delete &something;, which is needed if you use references rather than pointers. Again, it just seems more natural (to me, at least), that objects managing memory use pointers.
It's not convenient to write exception-safe code I think.
The first version of Object::operator=(Object const&) might be:
Object& operator=(Object const& other)
{
ObjectPrivate *p = &m_Private;
m_Private = other.m_Private; // Dangerous sometimes
delete *p;
}
It's dangerous if ObjectPrivate::operator=(ObjectPrivate const&) throws exception. Then what about using a temporary variable? Aha, no way. operator=() has to be invoked if you want change m_Private.
So, void ObjectPrivate::swap(ObjectPrivate&) noexcept can act as our savior.
Object& operator=(Object const& other)
{
ObjectPrivate *tmp = new ObjectPrivate(other.m_Private);
m_Private.swap(*tmp); // Well, no exception.
delete tmp;
}
Then consider the implementation of void ObjectPrivate::swap(ObjectPrivate&) noexcept. Let's assume that ObjectPrivate might contain a class instance without swap() noexcept or operator=() noexcept. I think it's hard.
Alright then, this assumption is too strict and not correct sometimes. Even so, it's not necessary for ObjectPrivate to provide swap() noexcept in most cases, because it's usually a helper structure to centralize data.
By contrast, pointer can save a lot of brain cells.
Object& operator=(Object const& other)
{
ObjectPrivate *tmp = new ObjectPrivate(*other.p_Private);
delete p_Private;
p_Private = tmp; // noexcept ensured
}
It's much more elegant if smart pointers are used.
Object& operator=(Object const& other)
{
p_Private.reset(new ObjectPrivate(*other.p_Private));
}
Some quick and obvious additions:
Pro
The reference must not be 0.
The reference may not be assigned another instance.
Class responsibilities/implementation are simpler due to fewer variables.
The compiler could make some optimizations.
Con
The reference may not be assigned another instance.
The reference will be too restrictive for some cases.
I want a safe C++ pointer container similar to boost's scoped_ptr, but with value-like copy semantics. I intend to use this for a very-rarely used element of very-heavily used class in the innermost loop of an application to gain better memory locality. In other words, I don't care about performance of this class so long as its "in-line" memory load is small.
I've started out with the following, but I'm not that adept at this; is the following safe? Am I reinventing the wheel and if so, where should I look?
template <typename T>
class copy_ptr {
T* item;
public:
explicit copy_ptr() : item(0) {}
explicit copy_ptr(T const& existingItem) : item(new T(existingItem)) {}
copy_ptr(copy_ptr<T> const & other) : item(new T(*other.item)) {}
~copy_ptr() { delete item;item=0;}
T * get() const {return item;}
T & operator*() const {return *item;}
T * operator->() const {return item;}
};
Edit: yes, it's intentional that this behaves pretty much exactly like a normal value. Profiling shows that the algorithm is otherwise fairly efficient but is sometimes hampered by cache misses. As such, I'm trying to reduce the size of the object by extracting large blobs that are currently included by value but aren't actually used in the innermost loops. I'd prefer to do that without semantic changes - a simple template wrapper would be ideal.
No it is not.
You have forgotten the Assignment Operator.
You can choose to either forbid assignment (strange when copying is allowed) by declaring the Assignment Operator private (and not implementing it), or you can implement it thus:
copy_ptr& operator=(copy_ptr const& rhs)
{
using std::swap;
copy_ptr tmp(rhs);
swap(this->item, tmp.item);
return *this;
}
You have also forgotten in the copy constructor that other.item may be null (as a consequence of the default constructor), pick up your alternative:
// 1. Remove the default constructor
// 2. Implement the default constructor as
copy_ptr(): item(new T()) {}
// 3. Implement the copy constructor as
copy_ptr(copy_ptr const& rhs): item(other.item ? new T(*other.item) : 0) {}
For value-like behavior I would prefer 2, since a value cannot be null. If you go for allowing nullity, introduces assert(item); in both operator-> and operator* to ensure correctness (in debug mode) or throw an exception (whatever you prefer).
Finally the item = 0 in the destructor is useless: you cannot use the object once it's been destroyed anyway without invoking undefined behavior...
There's also Roger Pate's remark about const-ness propagation to be more "value-like" but it's more a matter of semantics than correctness.
You should "pass on" the const-ness of the copy_ptr type:
T* get() { return item; }
T& operator*() { return *item; }
T* operator->() { return item; }
T const* get() const { return item; }
T const& operator*() const { return *item; }
T const* operator->() const { return item; }
Specifying T isn't needed in the copy ctor:
copy_ptr(copy_ptr const &other) : item (new T(*other)) {}
Why did you make the default ctor explicit? Nulling the pointer in the dtor only makes sense if you plan on UB somewhere...
But these are all minor issues, what you have there is pretty much it. And yes, I've seen this invented many times over, but people tend to tweak the semantics just slightly each time. You might look at boost::optional, as that's almost what you have written here as you present it, unless you're adding move semantics and other operations.
In addition to what Roger has said, you can Google 'clone_ptr' for ideas/comparisons.
I have a class that should hold a reference to some data, without owning that data (i.e. the actual data is guaranteed not to go out of scope). In particular, the class cannot make a copy – the data is easily several gigabytes in size.
Now, the usual implementation (I assume) is to have a reference to the data:
struct holder_ref {
type const& value;
holder_ref(type const& value) : value(value) { }
};
(Please note that the constness has absolutely no bearing on the problem).
Now, I absolutely need this class to be assignable (i.e. have a working operator =). I thought this was a fairly common problem but I can’t remember how (if ever) I’ve solved it before.
The problem is that a reference cannot be assigned and there’s simply no way around this. The only solution I’ve come up with uses placement new in place of the assignment operator:
// x = other_x; gets replaced with:
x.~T();
new (&x) T(other_x);
Now, this works and is standard compliant. But it sure is ugly. No – inacceptable.
So I’m searching for alternatives. One idea is to use pointers, but I’m unsure whether my constructor is actually guaranteed to work (and passing a pointer is impossible due to the interface I have to adhere to):
struct holder_ptr {
type const* value;
// Is this legal?
holder_ptr(type const& value = 0) : value(&value) { }
};
But I’d rather use a reference, if at all possible. Only – how to implement the assignment operator?
struct holder_ref {
type const& value;
holder_ref(type const& value = 0) : value(value) { }
holder_ref& operator =(holder_ref const& other) {
// Now what?!
return *this;
}
};
As a test case, consider the following code:
int main() {
int const TEST1 = 23;
int const TEST2 = 13;
int const TEST3 = 42;
std::vector<holder_ptr> hptr(1);
std::vector<holder_ref> href(2);
// Variant 1. Pointer.
hptr[0] = holder_ptr(TEST1);
// Variant 2. Placement new.
href[0].~holder_ref();
new (&href[0]) holder_ref(TEST2);
// Variant 3. ???
href[1] = holder_ref(TEST3);
assert(*hptr[0].value == TEST1); // Works (?)
assert(href[0].value == TEST2); // Works
assert(href[1].value == TEST3); // BOOM!
}
(Also, just to make this clear – the type we’re talking about is non-POD and I need a standard compliant solution.)
I don't see anything wrong with using a holder_ptr. It can be implemented something like so:
struct bad_holder : std::exception { };
struct holder_ptr {
holder_ptr() : value(0) { }
holder_ptr(type const& value) : value(&value) { }
type const& get() {
if (value == 0) throw bad_holder();
return *value;
}
private:
type const* value;
};
So long as you always assign to the pointer from a reference, you know that you have a valid object (that, or you ended up with a "null reference" previously, in which case you have other, bigger problems since you'll already have invoked undefined behavior).
With this solution, the interface is implemented entirely in terms of references, but under the hood a pointer is used so that the type is assignable. The use of references in the interface ensures there are none of the concerns that come with using pointers (namely, you never have to worry whether the pointer is null).
Edit: I've updated the example to allow for the holder to be default constructible.
I'd use the pointer holder. But if you are dead set against that, how about hiding your placement new operator=:
holder_ref& operator =(holder_ref const& other) {
new (this) holder_ref(other);
return *this;
}
Is a TR1 weak_ptr standard compliant enough?
I'm in the process of writing a smart pointer countedptr and I've hit a speed bump. The basic function of countedptr is to work like any other smart pointer and also have a count of how many pointers are pointing to a single object. So far, the code is:
[SOLVED]
#include "std_lib_facilities.h"
template <class T>
class counted_ptr{
private:
T* pointer;
int* count;
public:
counted_ptr(T* p = 0, int* c = new int(1)) : pointer(p), count(c) {} // default constructor
explicit counted_ptr(const counted_ptr& p) : pointer(p.pointer), count(p.count) { ++*count; } // copy constructor
~counted_ptr() { --*count; delete pointer; }
counted_ptr& operator=(const counted_ptr& p)
{
pointer = p.pointer;
count = p.count;
++*count;
return *this;
}
T* operator->() const{ return pointer; }
T& operator*() const { return *pointer; }
int Get_count() const { return *count; }
};
int main()
{
counted_ptr<double> one;
counted_ptr<double>two(one);
int a = one.Get_count();
cout << a << endl;
}
When I try to do something like
one->pointer = new double(5);
then I get a compiler error saying "request for member 'pointer' in '*(&one)->counted_ptr::operator->with T = double' which is of non-class type double".
I considered making a function to do this, and while I could make a function to allocate an array of T's, I can't think of a way of making one for allocating actual objects. Any help is appreciated, thanks.
Old Solution
What about another assignment operator?
counted_ptr& counted_ptr::operator=(T* p)
{
if (! --*count) { delete count; }
pointer = p;
count = new int(1);
return *this;
}
...
one = new double(5);
Also, your destructor always deletes a shared pointer, which is probably what caused *one to be a random nomber. Perhaps you want something like:
counted_ptr::~counted_ptr() { if (! --*count) { delete pointer; delete count; } }
New Solution
As you want repointing a counted_ptr (eg one = new double(5)) to update all related counted_ptrs, place both the pointer and the count in a helper class, and have your pointer class hold a pointer to the helper class (you might already be headed down this path). You could go two ways in filling out this design:
Make the helper class a simple struct (and a private inner class) and place all the logic in the outer class methods
Make counted_ptr the helper class. counted_ptr maintains a reference count but doesn't automatically update the count; it's not a smart pointer, it only responds to release and retain messages. If you're at all familiar with Objective-C, this is basically its traditional memory management (autoreleasing aside). counted_ptr may or may not delete itself when the reference count reaches 0 (another potential difference from Obj-C). counted_ptrs shouldn't be copyable. The intent is that for any plain pointer, there should be at most one counted_ptr.
Create a smart_ptr class that has a pointer to a counted_ptr, which is shared among smart_ptr instances that are supposed to hold the same plain pointer. smart_ptr is responsible for automatically updating the count by sending its counted_ptr release and retain methods.
counted_ptr may or may not be a private inner class of shared_ptr.
Here's an interface for option two. Since you're doing this as an exercise, I'll let you fill out the method definitions. Potential implementations would be similar to what's already been posted except that you don't need a copy constructor and copy assignment operator for counted_ptr, counted_ptr::~counted_ptr doesn't call counted_ptr::release (that's smart_ptr::~smart_ptr's job) and counted_ptr::release might not free counted_ptr::_pointer (you might leave that up to the destructor).
// counted_ptr owns its pointer an will free it when appropriate.
template <typename T>
class counted_ptr {
private:
T *_pointer;
size_t _count;
// Make copying illegal
explicit counted_ptr(const counted_ptr&);
counted_ptr& operator=(const counted_ptr<T>& p);
public:
counted_ptr(T* p=0, size_t c=1);
~counted_ptr();
void retain(); // increase reference count.
bool release(); // decrease reference count. Return true iff count is 0
void reassign(T *p); // point to something else.
size_t count() const;
counted_ptr& operator=(T* p);
T& operator*() const;
T* operator->() const;
};
template <typename T>
class smart_ptr {
private:
counted_ptr<T> *_shared;
void release(); // release the shared pointer
void retain(); // retain the shared pointer
public:
smart_ptr(T* p=0, int c=1); // make a smart_ptr that points to p
explicit smart_ptr(counted_ptr<T>& p); // make a smart_ptr that shares p
explicit smart_ptr(smart_ptr& p); // copy constructor
~smart_ptr();
// note: a smart_ptr's brethren are the smart_ptrs that share a counted_ptr.
smart_ptr& operator=(smart_ptr& p); /* Join p's brethren. Doesn't alter pre-call
* brethren. p is non-const because this->_shared can't be const. */
smart_ptr& operator=(counted_ptr<T>& p); /* Share p. Doesn't alter brethren.
* p is non-const because *this isn't const. */
smart_ptr& operator=(T* p); // repoint this pointer. Alters brethren
size_t count() const; // reference count
T& operator*() const; // delegate these to _shared
T* operator->() const;
};
Hopefully, the only ambiguous points above are the intentional ones.
(Sorry, newbie here, and can't leave comments). What Adatapost added, "one=new double(5);" should work. One other change needed, though: the reference counting needs a little help.
...
~counted_ptr() {
--*count;
// deallocate objects whose last reference is gone.
if (!*count)
{
delete pointer;
delete count;
}
}
counted_ptr& operator=(const counted_ptr& p)
{
// be careful to accommodate self assignment
++*p.count;
// may lose a reference here
--*count;
if (!*count)
{
delete pointer;
delete count;
}
count=p.count;
pointer=p.pointer;
return *this;
}
Of course, there's some code repetition here. It might make sense to refactor that code into its own function, e.g.
private:
/** remove our reference */
void release()
{
--*count;
if (!*count)
{
delete pointer;
delete count;
}
}
Did you, perhaps, mean "one.pointer=new double(5);"? Writing "one->pointer=new double(5);" invokes counted_ptr<double>::operator->. That is, it is approximately equivalent to:
double *tmp = one.operator->(); // returns one.pointer
tmp->pointer = new double(5);
But a double pointer isn't a structure, and so it doesn't have a pointer member.
Since the immediate problem has already been solved, I want to offer something more long term:
As you continue to develop this code, you'll definitely want to offer it up for full review by experienced programmers, whether here or elsewhere. There were a few obvious problems with your code as you posted it, though outis has helped correct them. But even once your code all compiles and seems to work in your own tests, there may be tests and situations which you haven't yet learned to think about. Smart pointers can easily have subtle problems that don't show up until very specific situations. So you'll want others to look over your code to find anything which you may have missed.
Please don't take this as any kind of insult towards your current code. I'm just offering this as friendly advice to ensure you learn the most you can out of this project.
Unless you are not doing this for academic reasons, you might want to use consider using the use_count() member of boost::shared_ptr. It's not entirely efficient, but it does work and you're better off using something well tested, mature, and thread safe. If you are doing this for learning purposes, be sure to check out the treatment of Reference Counting and Smart Pointers in More Effective C++.
You need to decrement the count and possibly delete the pointer to the old value in operator = before you overwrite it. You also need 'delete count' everywhere you have 'delete pointer' to avoid leaking memory