shared_ptr<> is to weak_ptr<> as unique_ptr<> is to... what? - c++

In C++11, you can use a shared_ptr<> to establish an ownership relation with an object or variable and weak_ptr<> to safely reference that object in a non-owned way.
You can also use unique_ptr<> to establish an ownership relation with an object or variable. But what if other, non-owning objects want to also reference that object? weak_ptr<> isn't helpful in this case. Raw pointers are helpful but bring various downsides (e.g. they can be automatically initialized to nullptr but this is accomplished through techniques that are not consistent with the std::*_ptr<> types).
What is the equivalent of weak_ptr<> for non-owning references to objects owned via unique_ptr<>?
Here's a clarifying example that resembles something in a game I'm working on.
class World
{
public:
Trebuchet* trebuchet() const { return m_trebuchet.get(); }
private:
std::unique_ptr< Trebuchet > m_trebuchet;
};
class Victim
{
public:
Victim( Trebuchet* theTrebuchet ) : m_trebuchet( theTrebuchet ) {}
~Victim()
{
delete m_trebuchet; // Duh. Oops. Dumb error. Nice if the compiler helped prevent this.
}
private:
Trebuchet* m_trebuchet; // Non-owning.
};
shared_ptr< Victim > createVictim( World& world )
{
return make_shared< Victim >( world.trebuchet() );
}
Here we use a raw pointer to maintain a non-owning relationship with an object owned via unique_ptr<> elsewhere. But is raw the best we can do?
The hope is a type of pointer that:
Looks like the other modern pointer types. E.g. std::raw_ptr<T>.
Replaces raw pointers so that a codebase that uses modern pointer types throughout can find all pointers via a search for _ptr< (roughly).
Auto-initializes to nullptr.
Thus:
int* p; // Unknown value.
std::raw_ptr< int > p; // null.
Does this type already exist in C++ now, is it proposed for the future, or is another implementation broadly available in e.g. Boost?

The "notify" behavior of shared_ptr requires reference counting the reference count control block. shared_ptr's reference count control block(s) use separate reference counts for this. weak_ptr instances maintain references to this block, and weak_ptrs themselves prevent the reference count control block from being deleteed. The pointed-to object has its destructor called when the strong count goes to zero (which may or may not result in deleteion of the memory where that object was stored), and the control block is deleteed only when the weak reference count goes to zero.
unique_ptr's tenet is that it has zero overhead over a plain pointer. Allocating and maintaining reference count control blocks (to support weak_ptr-ish semantics) breaks that tenet. If you need behavior of that description, then you really want shared semantics, even if other references to the object are non-owning. There's still sharing going on in that case -- the sharing of the state of whether or not the object has been destroyed.
If you need a generic nonowning reference and don't need notification, use plain pointers or plain references to the item in the unique_ptr.
EDIT:
In the case of your example, it looks like Victim should ask for a Trebuchet& rather than a Trebuchet*. Then it's clear who owns the object in question.
class World
{
public:
Trebuchet& trebuchet() const { return *m_trebuchet.get(); }
private:
std::unique_ptr< Trebuchet > m_trebuchet;
};
class Victim
{
public:
Victim( Trebuchet& theTrebuchet ) : m_trebuchet( theTrebuchet ) {}
~Victim()
{
delete m_trebuchet; // Compiler error. :)
}
private:
Trebuchet& m_trebuchet; // Non-owning.
};
shared_ptr< Victim > createVictim( World& world )
{
return make_shared< Victim >( world.trebuchet() );
}

There is a genuine need for a standard pointer type to act as a non-owning, inexpensive, and well-behaved counterpoint to std::unique_ptr<>. No such pointer has been standardized yet, but a standard has been proposed and is under discussion by the C++ standards committee. The "World's Dumbest Smart Pointer", aka std::exempt_ptr<> would have the general semantics of other modern C++ pointer classes but would hold no responsibility either for owning the pointed-to object (as shared_ptr and unique_ptr do) or for correctly responding to the deletion of that object (as weak_ptr does).
Assuming that this feature is ultimately ratified by the committee, it would fully meet the need highlighted in this question. Even if it isn't ratified by the committee, the above linked document fully expresses the need and describes a complete solution.

unique_ptr's non-owing analog is a plain C pointer. What is different - C pointer doesn't know if the pointed data is still accessible. weak_ptr on the other hand does. But it is impossible to replace raw pointer with a pointer knowing about the validity of data without additional overhead (and weak_ptr does have that overhead). That implies C-style pointer is the best in terms of speed you can get as a non-owing analog for unique_ptr.

While you can't get a "weak" pointer to a uniquely owned object for free, the concept is useful and is used in a couple systems. See Chromium's WeakPtr and QT's QPointer for implementations.
Chromium's WeakPtr is implemented intrusively by storing a shared_ptr inside the weak-referenceable object and marking it invalid when the object is destroyed. WeakPtrs then reference that ControlBlock and check whether it's valid before handing out their raw pointer. I assume QT's QPointer is implemented similarly. Because ownership isn't shared, the original object is destroyed deterministically.
However, this means that dereferencing the WeakUniquePtr isn't thread-safe:
Thread 1:
unique_ptr<MyObject> obj(new MyObject);
thread2.send(obj->AsWeakPtr());
...
obj.reset(); // A
Thread2:
void receive(WeakUniquePtr<MyObject> weak_obj) {
if (MyObject* obj = weak_obj.get()) {
// B
obj->use();
}
}
If line A happens to run concurrently with line B, thread 2 will wind up using a dangling pointer. std::weak_ptr would prevent this problem by atomically taking a shared owning reference to the object before letting thread 2 use it, but that violates the assumption above that the object is owned uniquely. That means that any use of a WeakUniquePtr needs to be synchronized with the destruction of the real object, and the simplest way to do that is to require that they're done in a message loop on the same thread. (Note that it's still completely safe to copy the WeakUniquePtr back and forth across threads before using it.)
One could imagine using a custom deleter in std::unique_ptr to implement this using standard library types, but that's left as an exercise for the reader.

boost::optional<Trebuchet&>
As Billy ONeal pointed out in his answer you likely want to pass a Trebuchet& instead of a pointer. The problem with the reference is that you cannot pass a nullptr, boost::optional provides a way to have the equivilent of a nullptr. Further details on boost::optional are here: http://www.boost.org/doc/libs/1_54_0/libs/optional/doc/html/boost_optional/detailed_semantics.html
See also this question: boost::optional<T&> vs T*
Note: std::optional<T> is on track to make it into C++14 but std::optional<T&> is a separate proposal that is not in the current C++14 draft. Further details here: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3672.html

In the new C++ world with shared_ptr, weak_ptr, and unique_ptr you should not be storing long lived references to objects, like your trebuchet, using raw pointers or references. Instead World should have a shared_ptr to the trebuchet and Victim should store either a shared_ptr or a weak_ptr, depending on whether the trebuchet should stick around with the victim if the world goes away. Using a weak_ptr allows you to tell if the pointer is still valid (i.e. the world still exists), there is no way to do this with a raw pointer or reference.
When you use a unique_ptr you are declaring that only the World instance will own the trebuchet. Clients of the World class can use the World object's trebuchet by calling the "get" method but should not hold on to the reference or pointer returned by the method when they are done using it. Instead they should "borrow" the trebuchet every time they want to use it by calling the "get" method.
The above being said there could be instances where you want to store a reference or raw pointer for future use to avoid the overhead of the shared_ptr. But those instances are few and far between and you need to be completely sure that you won't use the pointer or reference after the World object that owns the trebuchet has gone away.

otn::raw::weak (from C++ Object Token Library) is non-owning, inexpensive, and well-behaved counterpoint to std::unique_ptr. Also in the library there is otn::safe::unique, a unique owner which can "notify" a non-owning otn::safe::weak about the deletion of the object.
#include <otn/all.hpp>
#include <iostream>
int main()
{
using namespace std;
using namespace otn;
raw::weak_optional<int> raw_weak;
if (!raw_weak)
cout << "raw_weak is empty" << endl;
cout << "--- create object in std_unique..." << endl;
auto std_unique = std::make_unique<int>(42);
raw_weak = std_unique;
if (std_unique)
cout << "std_unique is not empty" << endl;
if (raw_weak)
cout << "raw_weak is not empty" << endl;
cout << "--- move std_unique to safe_unique..." << endl;
safe::unique_optional<int> safe_unique = std::move(std_unique);
if (!std_unique)
cout << "std_unique is empty" << endl;
if (raw_weak)
cout << "raw_weak is not empty, it is observs safe_unique" << endl;
safe::weak_optional<int> safe_weak = safe_unique;
if (safe_unique)
cout << "safe_unique is not empty" << endl;
if (!safe_weak.expired())
cout << "safe_weak is not expired" << endl;
cout << "--- destroy object in safe_unique..." << endl;
utilize(std::move(safe_unique));
if (!safe_unique)
cout << "safe_unique is empty" << endl;
if (safe_weak.expired())
cout << "safe_weak is expired, it is not dangling" << endl;
if (raw_weak)
cout << "raw_weak is not empty, it is dangling!!!" << endl;
}
Output:
raw_weak is empty
--- create object in std_unique...
std_unique is not empty
raw_weak is not empty
--- move std_unique to safe_unique...
std_unique is empty
raw_weak is not empty, it is observs safe_unique
safe_unique is not empty
safe_weak is not expired
--- destroy object in safe_unique...
safe_unique is empty
safe_weak is expired, it is not dangling
raw_weak is not empty, it is dangling!!!

A function taking a raw pointer or reference implicitly promises not to hold on to a copy of that pointer after the function has returned. In return the caller promises that the pointer is valid (or nullptr) until the callee has returned.
If you want to hold on to the pointer, you are sharing it (and should use shared_ptr). A unique_ptr manages a single copy of the pointer. You use raw pointers (or references) to refer to call functions involving that object.
This is the same for shared_ptr objects. weak_ptr only comes into play when you want to have an additional reference to the pointed too object that outlives the involved function. The main purpose of weak_ptr is to break reference cycles where two objects hold references to each other (and are therefore never released).
Remember however that taking shared_ptr or weak_ptr implies that the function taking that parameter will (optionally) modify some other object to retain a reference to the pointed to object that outlives the invocation of the function. In the vast majority of cases you use raw pointer (if nullptr is a valid value) or ref (when a value is guaranteed) even for shared_ptr or weak_ptr.

now you hava noshared_ptr --
https://github.com/xhawk18/noshared_ptr
noshared_ptr<T> -- a new type of unique ptr
noweak_ptr<T> -- weak ptr for the noshared_ptr

Related

Why is there no "weak pointer" for raw pointer? Or is there?

Shared pointers are good idea, no doubt. But as long as a large scale program includes raw pointers, I think there is a big risk in using shared pointers. Mainly, you will loose control of the real life-cycle of pointers to objects that hold raw pointers, and bugs will occur in locations which are more difficult to find and debug.
So my question is, was there no attempt to add to modern c++ a "weak pointer" which does not depend on using shared pointers? I mean just a pointer which becomes NULL when deleted in any part of the program. Is there a reason not to use such a self-made wrapper?
To better explain what I mean, the following is such a "weak pointer" that I made. I named it WatchedPtr.
#include <memory>
#include <iostream>
template <typename T>
class WatchedPtr {
public:
// the only way to allocate new pointer
template <typename... ARGS>
WatchedPtr(ARGS... args) : _ptr (new T(args...)), _allocated (std::make_shared<bool>(true)) {}
WatchedPtr(const WatchedPtr<T>& other) : _ptr (other._ptr), _allocated (other._allocated) {}
// delete the pointer
void del () {delete _ptr; *_allocated = false;}
auto& operator=(const WatchedPtr<T> &other) { return *this = other; }
bool isNull() const { return *_allocated; }
T* operator->() const { return _ptr; }
T& operator*() const { return *_ptr; }
private:
T* _ptr;
std::shared_ptr <bool> _allocated;
};
struct S {
int a = 1;
};
int main () {
WatchedPtr<S> p1;
WatchedPtr<S> p2(p1);
p1->a = 8;
std::cout << p1.isNull () << std::endl;
std::cout << p2.isNull () << std::endl;
p2.del ();
std::cout << p1.isNull () << std::endl;
std::cout << p1.isNull () << std::endl;
return 0;
}
Result:
1
1
0
0
-Edited-
Thank you all. Some clarifications following the comments and answers so far:
The implementation I presented for WatchedPtr is merely to demonstrate what I mean: a pointer that does not get the copy from external allocation, cannot be deleted externally, and becomes null if it is deleted. The implementation is knowingly far from perfect and was not meant to be perfect.
Problem with mix of shared_ptr and raw pointers is very common: A* is held as raw pointer, thus created at some point of the program and explicitly deleted at some point of the program. B holds a A*, and B* is held as shared_ptr, thus B* has vague lifespan. Thus B may live long after the deletion of A* that B holds.
The main usage of "WatchedPtr" in my mind is defensive programing. i.e. check for null and do the best thing possible for continuity (and a debug error). shared_ptr can do it, but in a very dangerous way - it will hide and delay the problem.
There can also be a design usage for "WatchedPtr" (very few and explicit "owners"), but this is not the main idea. For that indeed shared pointers are doing the job.
The intention of "WatchedPtr" is not for replacing all existing raw pointers in the program at once. It is not the same effort as replacing to shared_ptr, which IMHO has be done for the whole program at once. Which is unrealistic for large scale programs.
Weak pointers rely on notifications from the smart pointer infrastructure, so you could never do this with actual raw pointers.
One could imagine an extension of, say, unique_ptr which supported weak pointers, certainly. Presumably the main reason that nobody rushed in to implement such a feature is that weak pointers are already at the "Use refcounting and everything should just work" end of the scale, while unique_ptr is at the "Manage your lifetimes through RAII or you're not a real C++ programmer" end of the scale. Weak pointers also require there to be a separate control block per allocation, meaning that the performance advantage of such a WatchedPtr would be minimal compared to shared_ptr.
I think there is a big risk in using shared pointers. Mainly, you will loose control of the real life-cycle of pointers to objects that hold raw pointers, and bugs will occur in locations which are more difficult to find and debug.
Then you say
just a pointer which becomes NULL when deleted in any part of the program.
Don't you see the contradiction?
You don't want to use shared pointer because the lifetime of objects are determined at runtime. So far so good.
However, you want a pointer that automatically becomes null when the owner deletes it. The problem is if the lifetime of your pointer is known, you should not need that at all! If you know when the lifetime of your pointer ends, then you should be able to remove all instances of that pointer, a have a mean to check if the pointer is dead.
If you have a pointer that you don't know when the owner will free it and have no way to check or no observable side effect for the point of view of the weak owner, then do you really have control over lifetime of your pointer? Not really.
In fact, your implementation rely on containing a shared pointer. This is enlightening in the sense that you need some form of shared ownership in order to implement a raw pointer that can have weak pointer to it. Then if you need shared ownership to implement a raw pointer with weak references, you are left with a shared pointer. That's why the existence of your proposed class is contradictory.
std::shared_ptr + std::weak_ptr is made to deal with the issue of "parts of your program don't know when the owner free the resouce". What you need is a single std::shared_ptr and multiple std::weak_ptr, so they know when the resource is freed. These classes have the infomation needed to check the lifetime of a variable at runtime.
Or if in the contrary you know the lifetime of your pointers, then use that knowledge and find a way to remove dangling pointers, or expose a way to check for dangling pointers.
Reading the answers and comments, along with C++ Core Guidelines by Bjarne Stroustrup & Herb Sutter, I have come to the following answer:
When following the guidelines, there is no need for a "WatchedPtr" which involves "new" and "delete". However, a way to track the validity of a raw pointer taken from a smart pointer, is still in question for me, for debug/QA purposes.
In details:
Raw pointers should continue to be used. For various reasons. However, explicit "new" and "delete" should not. The cases of calling "new" and "delete" should all be replaced by shared_ptr/unique_ptr.
At the place where a raw pointer is currently allocated, there is no point in replacing it by "WatchedPtr".
If replacing a raw pointer to something else where it is allocated, it will be in most cases to unique_ptr, and on the other cases to shared_ptr. The "WatchedPtr", if at all, will continue from that point, built from the shared/unique pointer.
Therefor I have posted a somewhat different question.

Non owning reference to deleteable object

What would the best practice to hold a non owning reference to a object, that can be deleted?
The first part is fairly simple, I simply using the stupid-smart pointer: observer_ptr. However, the last part makes it somewhat more difficult.
Example
Having this setup, to illustrate the need of my vector unique ptr
class Object
{
};
class Derrived : public Object
{
};
With the implementation of
vector<nonstd::observer_ptr<Object>> _observers;
vector<unique_ptr<Object>> _objects;
auto t = make_unique<Derrived>();
_observers.push_back(nonstd::make_observer(t.get()));
_objects.push_back(move(t));
// Same objects
cout << (_observers.at(0).get() == _objects.at(0).get()) << endl;
Issue
Now at any time, somewhere, one of the objects in _objects might be deleted.
I will simply illustrate this by deleting the first object in the vector:
_objects.erase(_objects.begin());
This will result in the _objects vector is empty. However, the _observers vector now points to a freed memory space.
Of course, I can simply delete the observer from _observers, but imagine having such observing references in different parts of my program.
Would there be any cleaner solution for this, and it this the right way to observe different objects?
Please let me know if the example at hand does not illustrate the problem (or any problem for that matter) that I described.
Your use-case sounds like a std::weak_ptr<Object> would be suitable non-owning representation. Of course, for a std::weak_ptr<T> the owning representation is std::shared_ptr<T>. However, since you’ll need to “pin” the object before you could access a std::weak_ptr<T> you’d have more than one owner anyway while accessing the pointer.
As stated in the comments, this is a typical use-case for std::weak_ptr:
std::weak_ptr is a smart pointer that holds a non-owning ("weak")
reference to an object that is managed by std::shared_ptr. It must be
converted to std::shared_ptr in order to access the referenced object.
Example:
vector<shared_ptr<Object>> objects;
objects.push_back(make_shared<Derived>());
weak_ptr<Object> ptr{ objects.back() };
auto sh_ptr = ptr.lock(); // increase reference count if object is still alive
if(sh_ptr) { // if object was not deleted yet
sh_ptr->doStuff(); // safely access the object, as this thread holds a valid reference
}
Today there is no way to make non-owning relationship to be enforced by compiler:
1. weak_ptr could be converted to shared_ptr
2. Everything else could be deleted.
3. Wrappers around weak_ptr that would be non convertible to shared_ptr would not work also: once reference to an object is retrieved it could be deleted too.

How to pass shared_ptr to class with lower lifetime?

I'd like to optimize my code. I have one class that has a shared_ptr data member. In some methods of this class, I create objects that need to use this member (just to get information from the object pointed by shared_ptr). I know that lifetime of these created objects is lower than in my main class.
How to pass this pointer? I think another shared_ptrs is unnecessary (because I have a warranty that the object will exist). So what should get my created classes? Should they get raw pointer? Weak_ptr? Or the best solution is getting shared_ptr (and incrementing its reference counter)? What is the most standard solution?
In this case when you know the life-time of your shared resource will outlive those that you pass the pointer to the correct thing to do is pass a reference or a raw pointer:
void func(object* o)
{
// do stuff with o
}
// ...
std::shared_ptr<object> sp;
// ...
func(sp.get()); // pass raw pointer
The main reason for this is that the function can be useful no matter what kind of smart pointer is managing the resource. By accepting the raw pointer your function is able to accept objects from shared pointers as well as unique pointers and any other third party smart pointer.
There is no benefit to passing in the smart pointer unless the function needs to modify the smart pointer itself.
A good set of guidelines being produced by Bjarne Straustrup & Herb Sutter can be found here: CppCoreGuidelines
The rule about passing raw pointers (or references):
F.7
Passing a smart pointer transfers or shares ownership and should only be used when ownership semantics are intended. A function that does not manipulate lifetime should take raw pointers or references instead.
Passing by smart pointer restricts the use of a function to callers that use smart pointers. A function that needs a widget should be able to accept any widget object, not just ones whose lifetimes are managed by a particular kind of smart pointer.
When passing the shared_ptr into a function that will not store the resource, pass it by reference:
void foo(const shared_ptr<T>& ptr)
{
// Basically just a pointer dereference
std::cout << ptr->bar() << '\n';
}
int main()
{
std::shared_ptr<T> ptr{std::make_shared<T>()};
foo(ptr);
}
That won't increment the reference count, but that's fine — you're effectively treating it as a raw pointer (because you're just temporarily inspecting the pointee) but in a way that's safe because if you accidentally copy it then you'll get the reference count increment that can save your life. :)
However, if foo needs to store any sort of handle to this object, then you should pass in the shared_ptr by copy … or consider using weak_ptr so that you at least get some semblance of safety.
The above contrived example is so simple that I'd actually make it the following:
void foo(const T& ptr)
{
std::cout << ptr.bar() << '\n';
}
int main()
{
std::shared_ptr<T> ptr{std::make_shared<T>()};
foo(*ptr.get());
}

Is there such thing as a weak_ptr that can't be locked (promoted to shared_ptr)? If not, why?

Maybe this question has been asked before, but I've never found a satisfactory answer. Also, for the purposes of simplicity assume I'm talking about a single-threaded application.
So, what I've heard a number of times is that if you have an object that is non-owned and whose lifetime is guaranteed, you should reference it with a raw pointer. The object's owner would use a unique_ptr, and hand out raw pointers as necessary.
But what if the object is non-owned, and the lifetime is not guaranteed? Then you can use a weak_ptr, yes. But then anyone who is handed a weak_ptr could be naughty and keep it locked, such that the object's owner can't cause the object to be destroyed. Sometimes this may not be a problem, but sometimes it is. For example, when the owned object represents some system resource which must be relinquished at a certain time.
You may say "well, then you should just make sure no one keeps the weak_ptr locked!" But that is just not ideal (in my opinion) from an OO design standpoint, as it creates a dependency between the "owner" object and any object that gets a weak_ptr from it. You might as well make the argument "you don't need to return const references; you should just make sure no one modifies the reference."
With Qt, you have the QPointer, which is basically what I'm looking for. It checks that the object hasn't been destroyed, but it can't prevent the object from being destroyed. I realize this isn't thread-safe, but again, I'm talking about the context of a single thread.
So why isn't there something similar for C++11? I'm sure I could make a wrapper around weak_ptr that accomplishes what I'm after. But I wonder if I'm going about this all wrong.
No. And it doesn't exist is because it's unsafe even for a single thread. Consider:
void some_function (super_weak_ptr foo)
{
foo->some_function();
}
What happens if some_function (through an indirect path) causes the object to be destroyed? And before you say that can never happen, yes it can. For example:
void got_some_data (some_type whatObject, some_other_type whatData)
{
super_weak_ptr object = findObject (whatObject);
if (object)
object->youGotMail (whatData);
}
Now, suppose the youGotMail function realizes that the object now got the last bit of data it needs and its job is complete, it might destroy that object, and now we're running a function on an object that no longer exists.
If you want a raw pointer, you know where to find one. It doesn't make much sense to create a "smart" pointer that's no safer than a raw pointer.
So if you're not managing the lifetime of an object, you need the ability to lock that object before you can do anything to that object.
You can do this with pure Standard C++ using shared_ptr<unique_ptr<T>>.
Observers received only a shared_ptr<const unique_ptr<T>>, allowing them to look but not touch. The owner, having a non-const smart pointer, can at any time call reset() on the unique_ptr to destroy the instance. At that time all the observers can also see that the unique_ptr has become empty.
Obvious threading and re-entrance caveats apply (you need to check the unique_ptr for having a valid pointer again after each callback you invoke, etc).
And if there should be multiple owners, it's a bit more work. You will need one shared_ptr<T*>, giving observers a shared_ptr<T* const>. And a separate shared_ptr<T> to manage the object lifetime. The shared_ptr<T*> will need to be manually filled with nullptr (The T*, not the shared_ptr) in the object's destructor.
There is no such thing, alas.
In 2009 I toyed with / explored such a smart pointer type that I called ZPtr, as I recall as a cleanup effort of some earlier code in that direction, in the context of supporting better file abstraction error handling than the silence treatment of the standard library's iostreams. The (earlier) idea was to not have any zombie objects around, by self-destroying when no further meaningful operations were possible, and this required access via a smart pointer that could detect the existence or not of the referent. Evidently it was not such a good idea at the time, because the article I sent to DDJ about it was rejected … by the silence treatment.
I think now that we have argument forwarding support in the language, the time for such a pointer may have come. It would be even better with possible overloading of the . operator. But the functionality will anyway have to be chosen very carefully.
The std::weak_ptr isn't really "locked", in spite of naming. It's just used to obtain a std::shared_ptr, if possible. And a std::shared_ptr readily supplies you with a raw pointer.
So you can choose to hand out not std::weak_ptr directly, but a wrapper that only provides a temporary raw pointer.
It will not be very thread safe though, and unlike a ZPtr it will not give the client code any idea of why the referent doesn't exist any more (when it doesn't). But it just may be all that you need. Let me get some coffee & a bite to eat, then I'll cook up an example.
Example:
#include <memory>
namespace cppx {
using std::shared_ptr;
using std::weak_ptr;
template< class Type >
class Poor_ptr
{
private:
struct Null {};
weak_ptr<Type> weak_p_;
public:
explicit operator bool() const { return not is_null(); }
friend
auto operator==( const Poor_ptr& p, Poor_ptr::Null* )
-> bool
{ return p.is_null(); }
friend
auto operator==( Poor_ptr::Null*, const Poor_ptr& p )
-> bool
{ return p.is_null(); }
friend
auto operator!=( const Poor_ptr& p, Poor_ptr::Null* )
-> bool
{ return not p.is_null(); }
friend
auto operator!=( Poor_ptr::Null*, const Poor_ptr& p )
-> bool
{ return not p.is_null(); }
auto is_null() const
-> bool
{ return (ptr_or_null() == nullptr); }
auto ptr_or_null() const
-> Type*
{
try
{
return weak_p_.lock().get();
}
catch( ... )
{
return nullptr;
}
}
auto ptr() const
-> Type*
{ return weak_p_.lock().get(); }
Poor_ptr( shared_ptr< Type > p )
: weak_p_( p )
{}
};
} // namespace cppx
#include <iostream>
using namespace std;
auto main() -> int
{
cout << boolalpha;
auto p = make_shared<int>( 42 );
cppx::Poor_ptr<int> pp = p;
cout
<< "That " << pp.ptr_or_null() << " is null is "
<< (pp == 0) << ", not " << !!pp << ".\n";
p.reset();
cout
<< "That " << pp.ptr_or_null() << " is null is "
<< (pp == 0) << ", not " << !!pp << ".\n";
}
Oh, and to cover the problem that David Schwartz mentions, that of the object disappearing in mid-call of some function, you can just provide a member function that executes a functor such as std::function with a raw pointer as argument, where the referred to object is guaranteed kept alive during that call (namely by having a local std::shared_ptr).
Then the client code programmer can choose whether to rely on an assumption that called functions will not destroy the object, or use the safer callback mechanism.

What are potential dangers when using boost::shared_ptr?

What are some ways you can shoot yourself in the foot when using boost::shared_ptr? In other words, what pitfalls do I have to avoid when I use boost::shared_ptr?
Cyclic references: a shared_ptr<> to something that has a shared_ptr<> to the original object. You can use weak_ptr<> to break this cycle, of course.
I add the following as an example of what I am talking about in the comments.
class node : public enable_shared_from_this<node> {
public :
void set_parent(shared_ptr<node> parent) { parent_ = parent; }
void add_child(shared_ptr<node> child) {
children_.push_back(child);
child->set_parent(shared_from_this());
}
void frob() {
do_frob();
if (parent_) parent_->frob();
}
private :
void do_frob();
shared_ptr<node> parent_;
vector< shared_ptr<node> > children_;
};
In this example, you have a tree of nodes, each of which holds a pointer to its parent. The frob() member function, for whatever reason, ripples upwards through the tree. (This is not entirely outlandish; some GUI frameworks work this way).
The problem is that, if you lose reference to the topmost node, then the topmost node still holds strong references to its children, and all its children also hold a strong reference to their parents. This means that there are circular references keeping all the instances from cleaning themselves up, while there is no way of actually reaching the tree from the code, this memory leaks.
class node : public enable_shared_from_this<node> {
public :
void set_parent(shared_ptr<node> parent) { parent_ = parent; }
void add_child(shared_ptr<node> child) {
children_.push_back(child);
child->set_parent(shared_from_this());
}
void frob() {
do_frob();
shared_ptr<node> parent = parent_.lock(); // Note: parent_.lock()
if (parent) parent->frob();
}
private :
void do_frob();
weak_ptr<node> parent_; // Note: now a weak_ptr<>
vector< shared_ptr<node> > children_;
};
Here, the parent node has been replaced by a weak pointer. It no longer has a say in the lifetime of the node to which it refers. Thus, if the topmost node goes out of scope as in the previous example, then while it holds strong references to its children, its children don't hold strong references to their parents. Thus there are no strong references to the object, and it cleans itself up. In turn, this causes the children to lose their one strong reference, which causes them to clean up, and so on. In short, this wont leak. And just by strategically replacing a shared_ptr<> with a weak_ptr<>.
Note: The above applies equally to std::shared_ptr<> and std::weak_ptr<> as it does to boost::shared_ptr<> and boost::weak_ptr<>.
Creating multiple unrelated shared_ptr's to the same object:
#include <stdio.h>
#include "boost/shared_ptr.hpp"
class foo
{
public:
foo() { printf( "foo()\n"); }
~foo() { printf( "~foo()\n"); }
};
typedef boost::shared_ptr<foo> pFoo_t;
void doSomething( pFoo_t p)
{
printf( "doing something...\n");
}
void doSomethingElse( pFoo_t p)
{
printf( "doing something else...\n");
}
int main() {
foo* pFoo = new foo;
doSomething( pFoo_t( pFoo));
doSomethingElse( pFoo_t( pFoo));
return 0;
}
Constructing an anonymous temporary shared pointer, for instance inside the arguments to a function call:
f(shared_ptr<Foo>(new Foo()), g());
This is because it is permissible for the new Foo() to be executed, then g() called, and g() to throw an exception, without the shared_ptr ever being set up, so the shared_ptr does not have a chance to clean up the Foo object.
Be careful making two pointers to the same object.
boost::shared_ptr<Base> b( new Derived() );
{
boost::shared_ptr<Derived> d( b.get() );
} // d goes out of scope here, deletes pointer
b->doSomething(); // crashes
instead use this
boost::shared_ptr<Base> b( new Derived() );
{
boost::shared_ptr<Derived> d =
boost::dynamic_pointer_cast<Derived,Base>( b );
} // d goes out of scope here, refcount--
b->doSomething(); // no crash
Also, any classes holding shared_ptrs should define copy constructors and assignment operators.
Don't try to use shared_from_this() in the constructor--it won't work. Instead create a static method to create the class and have it return a shared_ptr.
I've passed references to shared_ptrs without trouble. Just make sure it's copied before it's saved (i.e., no references as class members).
Here are two things to avoid:
Calling the get() function to get the raw pointer and use it after the pointed-to object goes out of scope.
Passing a reference of or a raw pointer to a shared_ptr should be dangerous too, since it won't increment the internal count which helps keep the object alive.
We debug several weeks strange behavior.
The reason was:
we passed 'this' to some thread workers instead of 'shared_from_this'.
Not precisely a footgun, but certainly a source of frustration until you wrap your head around how to do it the C++0x way: most of the predicates you know and love from <functional> don't play nicely with shared_ptr. Happily, std::tr1::mem_fn works with objects, pointers and shared_ptrs, replacing std::mem_fun, but if you want to use std::negate, std::not1, std::plus or any of those old friends with shared_ptr, be prepared to get cozy with std::tr1::bind and probably argument placeholders as well. In practice this is actually a lot more generic, since now you basically end up using bind for every function object adaptor, but it does take some getting used to if you're already familiar with the STL's convenience functions.
This DDJ article touches on the subject, with lots of example code. I also blogged about it a few years ago when I first had to figure out how to do it.
Using shared_ptr for really small objects (like char short) could be an overhead if you have a lot of small objects on heap but they are not really "shared". boost::shared_ptr allocates 16 bytes for every new reference count it creates on g++ 4.4.3 and VS2008 with Boost 1.42. std::tr1::shared_ptr allocates 20 bytes. Now if you have a million distinct shared_ptr<char> that means 20 million bytes of your memory are gone in holding just count=1. Not to mention the indirection costs and memory fragmentation. Try with the following on your favorite platform.
void * operator new (size_t size) {
std::cout << "size = " << size << std::endl;
void *ptr = malloc(size);
if(!ptr) throw std::bad_alloc();
return ptr;
}
void operator delete (void *p) {
free(p);
}
Giving out a shared_ptr< T > to this inside a class definition is also dangerous.
Use enabled_shared_from_this instead.
See the following post here
You need to be careful when you use shared_ptr in multithread code. It's then relatively easy to become into a case when couple of shared_ptrs, pointing to the same memory, is used by different threads.
The popular widespread use of shared_ptr will almost inevitably cause unwanted and unseen memory occupation.
Cyclic references are a well known cause and some of them can be indirect and difficult to spot especially in complex code that is worked on by more than one programmer; a programmer may decide than one object needs a reference to another as a quick fix and doesn't have time to examine all the code to see if he is closing a cycle. This hazard is hugely underestimated.
Less well understood is the problem of unreleased references. If an object is shared out to many shared_ptrs then it will not be destroyed until every one of them is zeroed or goes out of scope. It is very easy to overlook one of these references and end up with objects lurking unseen in memory that you thought you had finished with.
Although strictly speaking these are not memory leaks (it will all be released before the program exits) they are just as harmful and harder to detect.
These problems are the consequences of expedient false declarations: 1. Declaring what you really want to be single ownership as shared_ptr. scoped_ptr would be correct but then any other reference to that object will have to be a raw pointer, which could be left dangling. 2. Declaring what you really want to be a passive observing reference as shared_ptr. weak_ptr would be correct but then you have the hassle of converting it to share_ptr every time you want to use it.
I suspect that your project is a fine example of the kind of trouble that this practice can get you into.
If you have a memory intensive application you really need single ownership so that your design can explicitly control object lifetimes.
With single ownership opObject=NULL; will definitely delete the object and it will do it now.
With shared ownership spObject=NULL; ........who knows?......
If you have a registry of the shared objects (a list of all active instances, for example), the objects will never be freed. Solution: as in the case of circular dependency structures (see Kaz Dragon's answer), use weak_ptr as appropriate.
Smart pointers are not for everything, and raw pointers cannot be eliminated
Probably the worst danger is that since shared_ptr is a useful tool, people will start to put it every where. Since plain pointers can be misused, the same people will hunt raw pointers and try to replace them with strings, containers or smart pointers even when it makes no sense. Legitimate uses of raw pointers will become suspect. There will be a pointer police.
This is not only probably the worst danger, it may be the only serious danger. All the worst abuses of shared_ptr will be the direct consequence of the idea that smart pointers are superior to raw pointer (whatever that means), and that putting smart pointers everywhere will make C++ programming "safer".
Of course the mere fact that a smart pointer needs to be converted to a raw pointer to be used refutes this claim of the smart pointer cult, but the fact that the raw pointer access is "implicit" in operator*, operator-> (or explicit in get()), but not implicit in an implicit conversion, is enough to give the impression that this is not really a conversion, and that the raw pointer produced by this non-conversion is an harmless temporary.
C++ cannot be made a "safe language", and no useful subset of C++ is "safe"
Of course the pursuit of a safe subset ("safe" in the strict sense of "memory safe", as LISP, Haskell, Java...) of C++ is doomed to be endless and unsatisfying, as the safe subset of C++ is tiny and almost useless, as unsafe primitives are the rule rather than the exception. Strict memory safety in C++ would mean no pointers and only references with automatic storage class. But in a language where the programmer is trusted by definition, some people will insist on using some (in principle) idiot-proof "smart pointer", even where there is no other advantage over raw pointers that one specific way to screw the program state is avoided.