namespace rtp = rich_typed_ptr; Jeremy Maitin-Shepard wrote:
I believe multiple ownership in std::shared_ptr is not a goal in itself, but just a way to ensure that objects stay live as long as they're needed. In my opinion I do actually address the problem of multiple ownership by taking it away.
Well, regardless of how you want to look at it, shared_ptr allows an arbitrary acyclic ownership/"ensure pointers stay alive" graph, while unique_ptr only allows an ownership forest.
[...]
I think the primary use case for your proposed weak_ptr (possibly renamed param_ptr or arg_ptr) would be as the declared type for function parameters.
That, and as a way to create arbitrarily complex linked data structures without introducing ownership problems. Note how this makes it more similar to std::weak_ptr than you may have thought initially.
I think that's overselling it a bit. It only supports tree structures (with possible back pointers using raw pointers/your proposed weak_ptr). Certainly in many cases a tree structure is all that is needed, but sometimes a more general ownership graph is needed.
Let us be very precise. Ownership graphs using rtp::data_ptr allow rings and trees. Rings cannot overlap, but each ring node may at the same time be the root node of a tree. To be honest I find myself unable to imagine a data structure that needs even more complex ownership than that. Graph containers with a linked implementation for example only need tree-like ownership, with reference cycles closed by non-owning pointers. Regardless, this is just the *automatic* ownership part of the general pointer graph; using rtp::weak_ptr (to be renamed) one can create any arbitrary graph, and the user can implement ownership on top of that because it is possible to break a rtp::data_ptr chain using access through a rtp::weak_ptr. I like to call this meta-ownership and I have demonstrated its use for a cyclically owned data structure in my linked ring example.
Could you elaborate on why implicit conversion to my weak_ptr would be dangerous?
Because the weak_ptr may outlive the underlying object, and the implicit conversion makes it silent. The only context in which this can't happen is if the weak_ptr is used only as a function parameter type. A dangling reference is quite possible if used as a return type or struct/class member, or even a local variable. It is best to limit implicit conversions to cases that are guaranteed to be safe, and can't possibly result in a dangling reference. If it is possibly unsafe, there should be some syntactic cue indicating as much.
Since type deduction is only rudimental in C++11, there actually is such a warning signal:
auto x = weak(foo);
Sure, in this case there is a syntactic cue, although it is perhaps not strong enough: "weak reference" typically means a non-owning reference that nonetheless knows when the reference becomes invalid, and therefore is still safe. This is the case for std::weak_ptr, as well as weak references in most other languages. For that reason I think it would be better to choose a different name.
I agree that the name is too suggestive of semantics similar to std::weak_ptr. I'll change it. As for safety, I think std::weak_ptr is not really safer that rtp::weak_ptr because it's just as easy to produce a dangling pointer (in fact std takes only 3 lines of code to do it while rtp requires 4) and that's a disaster no matter what. The fact that it can detect that it's dangling does however make it easier to debug. Again, thanks for your feedback. -Julian