When I tried to replace Mozilla’s RefPtr with standard C++ smart-pointer to note one of my misusage of it, I used std::shard_ptr to do it. However, it didn’t work since there is a huge difference between Mozilla’s RefPtr and the std::shard_ptr
I’ve never noticed that because I never use smart-pointer before I worked for Mozilla. So it’s a perfect chance for me to get closer to look at their difference.
Reference count
Although they’re both using reference-count to track object and manage objects’ life-time by the count, they are counting on different things.
Suppose we have reference-counted pointers RefPtr<T>
and std::shard_ptr<T>
,
we will call it like RefPtr<Foo> p(new Foo(...))
and std::shard_ptr<Bar> q(new Bar(...))
RefPtr
When using RefPtr<T>
,
the total reference is counted on the Foo
objects.
That’s see an example below.
// Foo must provide reference-counted interface.
Foo* f = new Foo(...) // The total references will be counted on Foo object f.
RefPtr<Foo> p1(f) // the reference count of f is 1 now.
{
RefPtr<Foo> p2(f) // the reference count of f is 2 now.
}
// the reference count of f is back to 1 now since p2 is destroyed.
std::shard_ptr
When using std::shard_ptr<T>
,
the total reference is counted on the std::shard_ptr
itself.
That’s see an example below.
// Bar does NOT need to provide reference-counted interface.
Bar* b = new Bar(...)
std::shard_ptr<Bar> p1(f) // the reference count of p1 is 1 now.
{
std::shard_ptr<Bar> p2(p1) // the reference count of p1 and p2 is 2 now.
}
// the reference count of p1 is back to 1 now since p2 is destroyed.
std::shard_ptr<Bar> p3(b) // the reference count of p3 is 1 now.
Even worse, the above program will cause an error:
pointer being freed was not allocated.
The p1
and p3
both control the life-time of b
.
When p1
is destroyed, its reference-count is down to 0
,
so it will deallocate b
.
Nevertheless, When p3
is destroyed,
its reference-count is also down to 0
,
so it will deallocate b
again and cause an error:
Freeing an already-freed object
Thus, using
std::shard_ptr<Bar> p(new Bar(...))
to replace the following pattern should save your life.
// This is a bad pattern!
Bar* b = new Bar(...)
std::shard_ptr<Bar> p(f)
Sample code
That’s see the example-implementation of these two smart-pointers. Again, the key difference between RefPtr and std::shard_ptr is
RefPtr<T> p(new T(...))
: the reference is counted on the newedT
object so theclass T
must provide reference-counted interface.std::shard_ptr<Bar> q(new Bar(...))
: the reference is counted on theq
itself.
You can look here to see how to use it.
The above code is referenced from here