I recently hit an issue where neither unique_ptr
nor shared_ptr
seemed like the right solution.
So, I am considering inventing another kind of smart ptr (described below), but I thought to myself "surely I am not the first to want this."
So my high-level questions are:
- Does the below design make sense?
- Is there some way to accomplish this with existing smart ptrs (or other
std::
features), perhaps I am missing something?
Requirements:
- I want single ownership, much like
unique_ptr
- That is: only when the single owning pointer dies, should the underlying object be freed (unlike
shared_ptr
's behavior).
- That is: only when the single owning pointer dies, should the underlying object be freed (unlike
- I want some additional way to reference the object which is "aware" when the object gets deleted. So, something like
weak_ptr
, but to be used with a single ownership model. - I do not need thread safety
Motivating example:
Suppose I am iterating a list of interface pointers, calling methods on them. Some of those methods may result in items later in the list being deleted.
With plain pointers, I would get dangling references for those deleted items.
Proposed design:
Let's call the owning pointer my_ptr
and the non-owning reference my_weak_ptr
.
For a given object, we might have a diagram like this:
_______
my_ptr<Obj> owner ---------> |Obj* | -------> [Obj data ... ]
+----> |count|
| +--> |_____|
my_weak_ptr<Obj> A ---+ |
|
my_weak_ptr<Obj> B -----+
my_ptr
would have an interface largely identical to unique_ptr
.
Internally, it would store a pointer to a "control block" which is really just the "real" pointer and a refcount for the control block itself.
On destruction, my_ptr
would set the control block pointer to NULL and decrement the refcount (and delete the control block, if appropriate).
my_weak_ptr
would be copyable, and have some get()
method which would return the real Obj*
.
The user would be responsible for checking this for NULL before using it.
On destruction, my_weak_ptr
would decrement the count (and delete the control block, if appropriate).
The downside is doing two hops through memory for each access.
For my_ptr
, this could be mitigated by storing the true Obj*
internally as well, but the my_weak_ptr
references will always have to pay that double-hop cost.
Edit: Some related questions, from links given:
- Non-ownership copies of std::unique_ptr
- Is it possible / desirable to create non-copyable shared pointer analogue (to enable weak_ptr tracking / borrow-type semantics)?
- Better shared_ptr by distinct types for "ownership" and "reference"?
So it seems like there is demand for something like this, but no slam-dunk solutions. If thread safety is needed, shared_ptr
and weak_ptr
are the right choices, but if not, they add unnecessary overhead.
There is also boost::local_scoped_ptr
, but it is still a shared ownership model; I'd rather prevent copies of the owning pointer, like unique_ptr
.