shared_ptr and unique_ptr conversion - c++

I'm in the situation where I'm not sure which type of smart pointer to use because I'm not sure of all the use cases for my class. I could just use shared pointers but I'm not fond of the idea of passing shared pointers everywhere in my code when I don't necessarily need shared ownership. This article by Herb Sutter says that when in doubt, use unique_ptr and convert to shared_ptr when you have to. This is what I'd like to do but I'm unclear as to how this is supposed to be done, consider this example:
class Example
{
public:
Example(): _ptr(std::make_unique<Node>()) {}
std::unique_ptr<Node>& getPtr()
{
return _ptr;
}
private:
// I am unsure if I will eventually need shared ownership or not
std::unique_ptr<Node> _ptr;
};
Example* example = new Example();
// Some function somewhere
void f()
{
// I've decided I need shared ownership, converting
std::shared_ptr<Node> ptr(std::move(example->getPtr()));
// Oops, example is no longer valid...
}
If someone has a better idea of how to deal with situations like this I'd be glad to hear it.

I think you are asking a kind of optimization question. You want Example to use unique_ptr because it has simpler and more efficient semantics (paraphrasing your referenced article). But, when the need arises, you wish to allow the pointer to be converted to shared_ptr.
Example should simply provide an interface for that, and itself needs to convert from unique_ptr to shared_ptr, when its user invokes that interface. You could use state pattern to capture whether the instance is in unique_ptr mode or shared_ptr mode.
class Example
{
struct StateUnique;
struct StateShared;
struct State {
State (std::unique_ptr<State> &s) : _state(s) {}
virtual ~State () = default;
virtual Node & getPtr () = 0;
virtual std::shared_ptr<Node> & getShared() = 0;
std::unique_ptr<State> &_state;
};
struct StateUnique : State {
StateUnique (std::unique_ptr<State> &s)
: State(s), _ptr(std::make_unique<Node>()) {}
Node & getPtr () { return *_ptr.get(); }
std::shared_ptr<Node> & getShared() {
_state = std::make_unique<StateShared>(*this);
return _state->getShared();
}
std::unique_ptr<Node> _ptr;
};
struct StateShared : State {
StateShared (StateUnique &u)
: State(u._state), _ptr(std::move(u._ptr)) {}
Node & getPtr () { return *_ptr.get(); }
std::shared_ptr<Node> & getShared() { return _ptr; }
std::shared_ptr<Node> _ptr;
};
public:
Example(): _state(std::make_unique<StateUnique>(_state)) {}
Node & getNode() { return _state->getPtr(); }
std::shared_ptr<Node> & getShared() { return _state->getShared(); }
private:
std::unique_ptr<State> _state;
};
If the state machine looks scary (which it should, since it is over-engineered), then you can just maintain two pointers in the Example, and your methods which need to test which one it needs to use.
class Example
{
public:
Example(): _u_node(std::make_unique<Node>()) {}
Node & getNode() { return _u_node ? *_u_node.get() : *_s_node.get(); }
std::shared_ptr<Node> & getShared() {
if (_u_node) _s_node = std::move(_u_node);
return _s_node;
}
private:
std::unique_ptr<Node> _u_node;
std::shared_ptr<Node> _s_node;
};

If you have a class, say UniqueResourceHolder, it may be implemented as follows:
class UniqueResourceHolder{
public:
std::unique_ptr<Widget> ptr;
};
Later, if you want to get said resource from UniqueResourceHolder and put it in a SharedResourceHolder that looks as follows:
class SharedResourceHolder{
public:
std::shared_ptr<Widget> ptr;
};
the code to do so may look like this:
{
UniqueResourceHolder urh;
SharedResourceHolder srh;
//initialization of urh.ptr
srh.ptr = std::shared_ptr<Widget>(urh.release());
}
UniqueResourceHolder will no longer have the Widget it once did, so any attempt to use urh to get at the widget will be invalid (unless you repopulate it with a new one), but srh now will have that widget and will be willing to share. Anyway, that's how I understand the answer to the question in the link you provided. My own two cents is that it is also a trivial matter to replace occurrences of std::unique_ptr with std::shared_ptr; any business logic your program followed to ensure the uniqueness of the resource is still valid, but to go from business logic where you took advantage of the shared-nature of std::shared_ptr would take some time and focus to rework to a unique mindset.

Shared pointers are for shared resources. If you want to share resources I would declare everything shared from the beginning and not go through special conversions.
If you want to use unique pointer you are saying that there "must" only exist one pointer for the the resource you have allocated. That does not limit your way in using these objects. Why not rather use unique pointer and "move" your object through the classes instances and functions... If you have to convert to your pointer why not move it as unique...
Regarding performance: It is said, that compared to a primite pointer, the shared pointer is about 6 times slower. The unique pointer is about twice as slow. Of course I'm talking about accesses. If you really have performance critical portions of the code you can still get primitive pointers of these classes and operate. It does not even have to be a pointer, there are still the C++ References.
I think you should decide whether your object will be "shared" or "moved" and go on with the paradigm, instead of converting and changing all the time.
std::unique_ptr<Node>& getPtr()
{
return _ptr;
}
No, no. You are passing multiple references if you call that from different places. Use the "move" operator instead (With declarations like type& operator=(type&& other) for example) and pass your unique pointer.

Related

How to use shared_ptr to manage already ref-count managed objects?

if an object is already reference-counted (like glib in C), having obj_ref, obj_unref. All we have is a pointer like obj *p.
How can we use c++'s shared_ptr to manage the object so that we can have an uniform interface.
Ok, it seems that a lot of people have misunderstood my intension.
The greatest issue here is not about deleter. It's about inform of the original manager that I increased the refcount.
If I assigned or copied, only std::shared_ptr increased the refcount, but the original one did not. Is there anyway to inform it? So as the unref operation.
std::shared_ptr allows you to pass a custom deleter which is called when the owned object should be destroyed. You could use it to call obj_unref.
obj* p = create_obj();
p->obj_ref();
std::shared_ptr<obj> sp(p, [](auto p) {
p->obj_unref();
});
/* use sp normally, obj will be 'obj_unref'ed and deleted when sp goes out of scope */
I don't know how a obj is created and if it gets destroyed by obj_unref() when the count reaches 0, but I hope you see what I mean.
The idea is to increment objs internal reference count just once at the beginning, and decrement it just once when the last shared_ptr is destroyed.
Don't try to somehow duct tape std::shared_ptr's refcounting to your custom one, that won't end well. Just write a custom pointer:
struct objPtr {
objPtr()
: _ptr{nullptr} { }
objPtr(obj *ptr)
: _ptr{ptr} {
if(_ptr)
_ptr->obj_ref();
}
~objPtr() {
if(_ptr)
_ptr->obj_unref();
}
objPtr(objPtr const &orig)
: objPtr{orig._ptr} { }
objPtr &operator = (objPtr const &orig) {
obj *const oPtr = std::exchange(_ptr, orig._ptr);
_ptr->obj_ref();
oPtr->obj_unref();
return *this;
}
obj &operator * () { return *_ptr; }
obj const &operator * () const { return *_ptr; }
obj *operator -> () { return _ptr; }
obj const *operator -> () const { return _ptr; }
operator bool() const { return _ptr; }
bool operator ! () const { return !_ptr; }
private:
obj *_ptr;
};
Add move construction and assignment if you so wish.
When you want a shared_ptr, start with a unique_ptr. Then build up.
struct cleanup_obj {
// not called with nullptr:
void operator()(obj* t)const {
obj_unref(t);
}
};
using obj_unique_ptr = std::unique_ptr<T, cleanup_obj>;
using obj_shared_ptr = std::shared_ptr<T>;
template<class T>
obj_unique_ptr<T> make_unique_refcount( T* t ) {
using ptr=obj_unique_ptr<T>;
if (!t) return ptr();
obj_ref(t);
return ptr(t);
}
template<class T>
obj_shared_ptr<T> make_shared_refcount( T* t ) {
return make_unique_refcount(t); // implicit convert does right thing
}
What did I do?
First, I wrote a unique_ptr wrapper, because we may as well be complete, and it solves the shared_ptr case via the unique_ptr->shared_ptr implicit conversion.
For unique_ptr, we have to say we aren't using the default object destroyer. In this case, we are using a stateless function object that knows how to obj_unref an obj*. The stateless function object keeps the overhead at zero.
For the null case, we don't first add a reference, as that is rude.
For shared_ptr, the fact that we have a working unique_ptr makes it a free function. shared_ptr will happily store the destroyer function that unique_ptr has. It doesn't have to be told it has a special object destroyer, because shared_ptr type erases object destruction by default. (This is because unique_ptr<T> is zero-overhead over a naked pointer, while shared_ptr<T> has unavoidable overhead of the reference counting block; the designers figured once you have that reference counting block, adding in a type-erased destruction function was not really expensive).
Note that our obj_unique_ptr<T> is also zero overhead over a naked pointer. Quite often you'll want one of these instead of the shared one.
Now, you can upgrade the obj_unique_ptr to a full on intrusive pointer, with less overhead than a shared_ptr, if you want.
template<class T>
struct obj_refcount_ptr : obj_unique_ptr<T> // public
{
// from unique ptr:
obj_refcount_ptr(obj_unique_ptr<T> p):obj_unique_ptr<T>(std::move(p)){}
obj_refcount_ptr& operator=(obj_unique_ptr<T> p){
static_cast<obj_unique_ptr<T>&>(*this)=std::move(p);
return *this;
}
obj_refcount_ptr(obj_refcount_ptr&&)=default;
obj_refcount_ptr& operator=(obj_refcount_ptr&&)=default;
obj_refcount_ptr()=default;
obj_refcount_ptr(obj_refcount_ptr const& o):
obj_refcount_ptr(make_unique_refcount(o.get())
{}
obj_refcount_ptr& operator=(obj_refcount_ptr const& o) {
*this = make_unique_refcount(o.get());
return *this;
}
};
which I think covers it. Now it is a zero-overhead reference counting intrusive smart pointer. These intrusive smart pointers can be converted toa std::shared_ptr<T> via implicit conversion, as they are still unique_ptrs. They are just unique_ptrs we have taught to copy themselves!
It does require moving from an obj_refcount_ptr to get a shared_ptr. We can fix this:
operator std::shared_ptr<T>() const {
return obj_refcount_ptr(*this);
}
which creatres an obj_refcount_ptr copy of *this and moves it into the shared_ptr. Only one add ref is called, and the remove ref is only called when the shared_ptr count goes to zero.
The general approach is to start with the simplest smart pointer (unique_ptr), get it right, then exploit its implementation to get us the shared_ptr and eventually the refcount_ptr. We can test the unique_ptr implementation in isolation, and its correctness makes testing the richer pointers easier.
The most simplest approach, the least invasive one with the minimal possibility of breaking something, is to simply write your own facade for the object, with the underlying object as a private member and providing simple wrappers to access it.
Then use a std::shared_ptr to that.
It's an incredibly bad idea to have the same objects in multiple smart pointer implementations as their ref counts can't know about each other. As soon as the ref count hits zero in one it will delete the object even if the other still holds refs.
If you really had to you could construct your smart pointers with custom deleters (that do nothing), but I really wouldn't recommend this approach.
Pick one implementation and stick to it.

Problems with shared_from_this in Constructor for Chained Calls

I understand why shared_from_this doesn't work in the constructor. I've found a number of posts on here clearly explaining why. I've also seen a workaround for it. My problem is related to this but I'm looking for an elegant workaround.
I quite like this kind of design
class Foo : public enable_shared_from_this<Foo> {
public:
typedef shared_ptr<Foo> Ptr;
Ptr setA(int) {/* .... */ return this->shared_from_this(); }
Ptr setB(int) {/* .... */ return this->shared_from_this(); }
Ptr setC(int) {/* .... */ return this->shared_from_this(); }
};
so I can daisy chain like this, which I find very readable
Foo::Ptr foo = make_shared<Foo>();
foo->setA(3)->setB(4)->setC(5);
However, my setX methods do more than just assign the value to a property, they might do slightly more complex things (like set other properties etc). So I'd like to use them in my constructor. i.e.
Foo::Foo(int a, int b, int c) {
setA(a);
setB(b);
setC(c);
}
Of course this crashes. However in my case I don't actually need a shared this pointer in my constructor. It's just a side-effect of my wanting to daisy chain later.
A dirty fix could be I just make a bunch of private setX_ methods which do the actual assignment and other tasks, but don't return anything. The constructor calls those. Then I have public setX methods simply call the private ones and then return the this->shared_from_this(). That's safe, but a bit of a PITA. Is it possible to check if a shared pointer to this already exists without crashing? i.e.
class Foo : public enable_shared_from_this<Foo> {
public:
typedef shared_ptr<Foo> Ptr;
Ptr setA(int) { /*.....*/ return getThis(); }
protected:
Ptr getThis() {
return safe_to_get_this ? this->shared_from_this : Ptr();
}
};
UPDATE
I should have made this clear in my original post, apologies for not doing so. The reason I'm using smart pointers is not so I can do daisy chaining. I usually use references for that if the situation permits.
But in this case Foo (and other classes) belong to a graph like structure, they have dependencies on each other, multiple parent-child-sibling relationships etc. So I use a mix between shared and weak pointers. But I need the methods to return shared_ptrs, so I can cast to weak or check against null if need be (They are created with factory methods, and there are find/get methods too which need checking against null). Basically it's a physics system with different types of particles and constraints between particles. I originally wrote this with my own smart pointer implementation many years ago, and now I'm upgrading it to c++11. I could make the setX methods return references, and have a single getThis() method return the shared pointer (which is what I was doing before), but then I'm worried it becomes a bit inconsistent with some methods returning smart pointers others returning references.
Foo::Ptr foo = World::create();
foo->setA().setB().setC();
foo = World::find(...);
if(foo) foo->setA().setB();
I just prefer the consistency of always returning pointers, as opposed to sometimes pointers and sometimes references. Unless there is a strict guideline for this that can be summarized succinctly.
UPDATE2
This is the (not very elegant) workaround I'm using currently. I was just wondering if there was a way of doing this without manually keeping track of _isInited;
class Foo : public enable_shared_from_this<Foo> {
public:
typedef shared_ptr<Foo> Ptr;
Foo() {
_isInited = false;
setA();
setB();
setC();
_isInited = true;
}
Ptr setA(int) {/* .... */ return getThis(); }
Ptr setB(int) {/* .... */ return getThis(); }
Ptr setC(int) {/* .... */ return getThis(); }
protected:
bool _isInited;
Ptr() {
return _isInited ? this->shared_from_this() : Ptr();
}
};
I'd like to add to the correct comment by #JoachimPileborg. I don't think your problem really has to do with the technicalities of an aspect of how to use enable_shared_from_this, but rather when to use (smart) pointers.
Consider the following code, showing two ways to use chained calls:
struct ptr_foo
{
ptr_foo *set_x(int x) { return this; }
ptr_foo *set_y(int y) { return this; }
};
struct ref_foo
{
ref_foo &set_x(int x) { return *this; }
ref_foo &set_y(int y) { return *this; }
};
int main()
{
ptr_foo pf;
pf.set_x(0)->set_y(1);
ref_foo rf;
rf.set_x(0).set_y(1);
return 0;
}
The first class, ptr_foo, uses raw pointers, and the second one, ref_foo, uses references.
To begin with, the second invocation,
rf.set_x(0).set_y(1);
seems to me much more consistent than the first one,
pf.set_x(0)->set_y(1);
for the common case of stack-based objects.
Furthermore, even if you prefer the first one, I don't think there's any reason to return a smart pointer, as
no allocation is taking place
the protocol is not meant for obtaining a store-able pointer to a ptr_foo by calling set_?; if someone does so, it is an abuse of the protocol, as it is just meant for chained calles.
Regarding point 2, you can't shut down protocol abuses hermetically anyway. E.g., consider
ptr_foo pf;
ptr_foo *ppf = &pf;
No matter how you design ptr_foo, the user now holds a pointer to an object of that type, which was not allocated dynamically, and which can be erroneously erased.

C++ base class with retain count

I m writing a library.
WITHOUT using smart pointer. Is it this class safe enough to emulate retain/release behaviour?
Or is there any library already doing things like this?
class FooBase {
private:
std::atomic<uint32_t> m_retainCount;
public:
FooBase()
{
m_retainCount = 1;
};
virtual ~FooBase()
{
assert(m_retainCount == 0); // Prevent from direct delete without release()
//clean-up if any
};
void *release()
{
m_retainCount--;
if (!m_retainCount)
delete this;
return this;
};
void *retain()
{
m_retainCount++;
return this;
};
};
Imagine if your thread gets swapped right after the branch in release and before the call to delete.
Another thread could come and request a retain, therefore obtaining a pointer to a soon to be deleted object.
To answer the second part, std::shared_ptr is thread-safe. It has the additional benefit of being able to use non-portable tricks internally because it's formally part of the compiler.

Indicating (non) transfer of ownership with unique_ptr

Suppose I have a class like this:
class Node {
public:
Node(Node* parent = 0) : mParent(parent) {}
virtual ~Node() {
for(auto p : mChildren) delete p;
}
// Takes ownership
void addChild(Node* n);
// Returns object with ownership
Node* firstChild() const;
// Does not take ownership
void setParent(Node* n) { mParent = n; }
// Returns parent, does not transfer ownership
Node* parent() const { return mParent; }
private:
list<Node*> mChildren;
Node* mParent;
};
I'd now like to use smart pointers and/or rvalue references to indicate where ownership is and isn't transferred.
My first guess would be to change mChildren to contain unique_ptrs, adapting the function signatures as follows.
// Takes ownership
void addChild(unique_ptr<Node> n);
// Returns object with ownership
unique_ptr<Node>& firstChild() const;
// Does not take ownership
void setParent(Node* n) { mParent = n; }
// Returns parent, does not transfer ownership
Node* parent() const { return mParent; }
Now, this would be kind of problematic when I need to pass the result of Node::firstChild() to some function that observes it, but does not take ownership, as I'd need to explicitly call .get() on the unique_ptr, which as I understand it, is not recommended.
What is the correct and recommended way to indicate ownership using unique_ptr without having to resort to using .get() and passing around bare pointers?
At first, I would use std::vector rather than std::list to contain the children. Unless you have a strong motivation for not using it, std::vector should be the default container. If you are worried about performance, don't be, because contiguous allocation done by std::vector is likely to cause higher cache hit rate, thus speeding up access enormously with respect to std::list, which implies a scattered allocation/access pattern.
Secondly, you are correct in having a std::vector<std::unique_ptr<Node>> for holding children, since it is reasonable to assume a node to hold ownership of its child nodes. All other pointers except the one accepted by addChild(), on the other hand, should be non-owning raw pointers.
This applies to the mParent pointer and to pointers returned by Node's member functions. In fact the, firstChild() member function could even return a reference, throwing an exception if the node has no children. This way you will create no confusion whatsoever about who is owning the returned object.
Returning a unique_ptr, or a reference to a unique_ptr, is not the correct idiom: unique pointers represent ownership, and you do not want to give ownership to clients of Node.
This is how your class could look like:
#include <vector>
#include <memory>
#include <stdexcept>
class Node {
public:
Node() : mParent(nullptr) { }
void addChild(std::unique_ptr<Node>&& ptr) {
mChildren.push_back(std::move(ptr));
ptr->setParent(this);
}
Node& firstChild() const {
if (mChildren.size() == 0) { throw std::logic_error("No children"); }
else return *(mChildren[0].get());
}
Node& parent() const {
if (mParent == nullptr) { throw std::logic_error("No parent"); }
else return *mParent;
}
private:
void setParent(Node* n) {
mParent = n;
}
std::vector<std::unique_ptr<Node>> mChildren;
Node* mParent;
};
You could of course decide to return non-owning, potentially null raw pointers instead of references if you want to avoid throwing exceptions. Or you could add a pair of hasParent() and getNumOfChildren() methods to retrieve information about a Node's state. That would allow clients to perform the check if they do not want to handle exceptions.

Implementing Smart Pointer - Dynamic Allocation with templates

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