
I think it would be useful to add the following features to shared_ptr: 1. Support for aliasing: if I have a shared_ptr<T> pt, to get a shared_ptr<Y> py (where T and Y are possibly unrelated types) such that pt and py share ownership. For example, if T is an array of elements of type Y, with this feature pointing an element from the array through a shared_ptr<Y> would keep the entire array afloat. Similar example is being able to point through a shared_ptr<Y> to a member of an object of class T, which would keep the entire T object afloat. 2. Support for obtaining (as a void *) the address of the original object passed to shared_ptr when the object was first created. That is, if we have a shared_ptr<T> pt( new T ), which is later converted to a shared_ptr<Y> py, I can call py.most_derived_ptr() to obtain the pointer returned by "new T" as a void *. Note that in general, most_derived_ptr has different semantics than dynamic_cast<void *>(py.get()): most_derived_ptr returns the same pointer that the deleter sees, while the dynamic_cast works with the pointer contained in the shared_ptr object. Also, dynamic_cast<void *>(pt.get()) requires that T is polymorphic, and shared_ptr has been carefuly designed to avoid this requirement. 3. Support for obtaining the std::type_info of the original object. I have not done any research on this, and it seems to me that these features are a natural extension of the shared_ptr framework so it's likely that others have had similar ideas before me. If anyone has experience with implementing or using these features, I'm very interested to get some feedback. Thanks, Emil Dotchevski

"Emil Dotchevski" <emildotchevski@hotmail.com> wrote in message news:BAY102-DAV10CB89F05952821C9EE4CBD4060@phx.gbl...
We currently have static_pointer_cast, dynamic_pointer_cast, and const_pointer_cast, which, naturally enough, perform static_cast, dynamic_cast, and const_cast on the underlying pointer. What you are asking for is basically a reinterpret_pointer_cast. If you can give a use case it seems natural enough. Joe Gottman

OK, add reinterpret_pointer_cast (I don't see why not, we need reinterpret_pointer_cast for the same reasons we need reinterpret_cast) to my request list, but the aliasing request is different: it doesn't simply treat a shared_ptr<T> as a shared_ptr<Y>. What I need is a shared_ptr constructor, which takes a shared_ptr and a raw pointer, and returns a shared_ptr of the type of the raw pointer which points the same object the raw pointer points, but shares ownership (the "pn" member of shared_ptr) with the original shared_ptr: template <class T> shared_ptr { .... template <class Y> shared_ptr( shared_ptr<Y> const & sp, T * p ): px(p), pn(sp.pn) { } .... }; It may be a good idea to make this constructor private, and to call it from a friend namespace-scope function with a name which clearly indicates what's going on: template <class T,class Y> shared_ptr<T> some_really_descriptive_name( shared_ptr<Y> const & sp, T * p ); --Emil Dotchevski ----- Original Message ----- From: "Joe Gottman" <jgottman@carolina.rr.com> To: <boost@lists.boost.org> Sent: Wednesday, October 25, 2006 5:06 PM Subject: Re: [boost] shared_ptr feature request

On 10/25/06, Emil Dotchevski <emildotchevski@hotmail.com> wrote:
Do you have a use case for reinterpret_pointer_cast? You don't need it to pass arbitrary shared_ptr<T>s into a function; shared_ptr<void> works fine for that.
Why do you want this? So it will delete both pointers? The code you've given would, I expect, have some serious problems. I think one of the pointers would get leaked and if it was the one from the original shared_ptr that leaked, a wrong deleter could be called on the new pointer. ~ SWMc

Any use case of reinterpret_cast between unrelated pointer types is a use case for reinterpret_pointer_cast.
You don't need it to pass arbitrary shared_ptr<T>s into a function; shared_ptr<void> works fine for that.
I thought the same thing but Peter Dimov pointed out that you need to accomodate shared_ptr<void const> as well as shared_ptr<void volatile> and shared_ptr<void const volatile>, etc. So, instead of taking shared_ptr<void const volatile> in the aliasing constructor, it's just better to take shared_ptr<Y>. It doesn't really matter because all we do with is use its pn member, which is independent of the type of the shared_ptr.
I am not sure what "so it will delete both pointers" means, but I'm reasonably sure that's not what I want. :)
The thing about shared_ptr is that the deleter has nothing to do with the px member of class shared_ptr. The px member is what operator*, operator->, and get() return. But px is not passed to the deleter when the object expires. Instead, the control block pointed to by the pn member of shared_ptr keeps the *original* pointer that was passed to the first of the (possibly) many shared_ptr objects that share ownership of a given object. The net effect of all this is that if somehow you change the px member of an existing shared_ptr, the object will not leak, and will be properly destroyed, no matter what px points to. With this in mind, consider this example: typedef int arr_type[10]; shared_ptr<arr_type> pa( new arr_type ); shared_ptr<int> pi( pa, &((*pa)[3]) ); //aliasing ctor pa.reset(); //won't destroy the array, pi keeps it afloat. (*pi) = 0; //zeroes the 4th int in the array. pi.reset(); //destroys the array passed to pa, not the int pi points. You can build a similar example for an object of class T being kept afloat by a shared_ptr<Y> to a member of type Y of the T object. --Emil Dotchevski

Err, my example is incorrect. Arrays need to be allocated with new[] and destroyed with delete[]. But the technique is still valid. The following was tested with a compiler so it works. :) struct arr_type { int a_[10]; arr_type() { std::cout << "arr_type constructed\n"; } ~arr_type() { std::cout << "arr_type destroyed\n"; } }; int main( int argc, char const * argv[] ) { boost::shared_ptr<arr_type> ap( new arr_type ); std::cout << "ap constructed\n"; boost::shared_ptr<int> ip( ap, &(ap->a_[3]) ); std::cout << "ip constructed\n"; std::cout << "ap reset begin\n"; ap.reset(); std::cout << "ap reset end\n"; std::cout << "ip reset begin\n"; ip.reset(); } Of course you'll need to add the following shared_ptr constructor: template <class Y> shared_ptr( shared_ptr<Y> const & r, T * x ): px(x), pn(r.pn) { } The output of the above program is this: arr_type constructed ap constructed ip constructed ap reset begin ap reset end ip reset begin arr_type destroyed ip reset end A similar example can be given with shared_ptr< std::list<int> >, or shared_ptr< std::vector<int> >. --Emil Dotchevski "Emil Dotchevski" <emildotchevski@hotmail.com> wrote in message news:BAY102-DAV1016EA8C29E6F1392C8129D4070@phx.gbl...

Emil Dotchevski wrote:
This has already been proposed in http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1851.pdf along with a few other features. On the one hand, when you need it, it's unquestionably useful and carries no additional overhead. I also like how the casts are now implementable via the public interface. On the other hand, it could be argued that this constructor makes it uncomfortably easy to construct a shared_ptr that can dangle (because the lifetime of p is not properly bounded by sp.)
participants (4)
-
Emil Dotchevski
-
Joe Gottman
-
me22
-
Peter Dimov