What is boost shared_ptr (shared_ptr <Y> const & r, T * p) used for?
boost::shared_ptr has an unusual constructor
template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p); and I'm a little puzzled by what it would be useful for. It basically owns r , but .get() will return p . not r.get() !
This means you can do something like this:
int main() { boost::shared_ptr<int> x(new int); boost::shared_ptr<int> y(x, new int); std::cout << x.get() << std::endl; std::cout << y.get() << std::endl; std::cout << x.use_count() << std::endl; std::cout << y.use_count() << std::endl; } And you get the following:
0x8c66008 0x8c66030 2 2 Note that pointers are separate, but both claim to have use_count of 2 (since they share ownership of the same object).
So an int belonging to x will exist as long as there is x or y around it. And if I understand the documents correctly, the second int will never be destroyed. I confirmed this with the following test program:
struct T { T() { std::cout << "T()" << std::endl; } ~T() { std::cout << "~T()" << std::endl; } }; int main() { boost::shared_ptr<T> x(new T); boost::shared_ptr<T> y(x, new T); std::cout << x.get() << std::endl; std::cout << y.get() << std::endl; std::cout << x.use_count() << std::endl; std::cout << y.use_count() << std::endl; } This outputs (as expected):
T() T() 0x96c2008 0x96c2030 2 2 ~T() So ... What is the use of this unusual construct that shares ownership of one pointer, but acts like another pointer (which it does not have) when used.
This is useful when you want to share a class member, and the class instance is already shared_ptr, for example:
struct A { int *B; // managed inside A }; shared_ptr<A> a( new A ); shared_ptr<int> b( a, a->B ); they share the usage score and stuff. This is an optimization of memory usage.
To extend leiz and piotr answers , this is a description of shared_ptr<> 'aliasing' from WG21, "Improving shared_ptr for C ++ 0x, version 2" :
III. Alias โโsupport
Advanced users often require the ability to create a
shared_ptrinstance ofp, which is another (master)shared_ptrq, but points to an object that is not the base of*q.*pcan be a member or*qelement, for example. This section offers an additional constructor that can be used for this purpose.An interesting side effect of this increased expressiveness is now that
*_pointer_castfunctions can be implemented in user code. Themake_sharedfactory function ismake_sharedLater in this document it can also be implemented using only theshared_ptrinterface through the aliasing constructor.Impact:
This function extends the
shared_ptrinterface in a backward compatible way, which increases its expressiveness and therefore it is highly recommended to add the standard in C ++ 0x. It does not introduce sources and problems with binary compatibility.Suggested text:
Add the following constructor to
shared_ptr[util.smartptr.shared]:template<class Y> shared_ptr( shared_ptr<Y> const & r, T * p );Add the following: [Util.smartptr.shared.const]:
template<class Y> shared_ptr( shared_ptr<Y> const & r, T * p );Effects: Creates an instance of
shared_ptrthat storesp, and has ownership ofr.Postconditions:
get() == p && use_count() == r.use_count().Throws: Nothing.
[Note. To avoid the possibility of turning the pointer, the user of this constructor must ensure that
premains valid at least until the ownership groupris destroyed. --end note.][Note. This constructor allows you to create an empty
shared_ptrinstance with a pointer that does not contain NULL. --end note.]
You can also use this to save dynamic casting pointers, i.e.:
class A {}; class B: public A {}; shared_ptr<A> a(new B); shared_ptr<B> b(a, dynamic_cast<B*>(a.get())); You may have a pointer to some driver or data structure of a lower-level api that can highlight additional data using a lower-level api or other means. In this case, it may be interesting to increase the value of use_count, but return additional data if the first pointer owns other data pointers.
For " shared_ptr<B> b(a, dynamic_cast<B*>(a.get())); "
I think it is not recommended to use a smart pointer.
Recommended conversion method of this type:
shared_ptr<B> b(a); Since the Boost document mentions that:
shared_ptr<T>can be implicitly converted toshared_ptr<U>whenever T * can be implicitly converted to U *. In particular,shared_ptr<T>implicitly convertible toshared_ptr<T> const, toshared_ptr<U>, where U is the available base of T andshared_ptr<void>.
In addition to this, we also have dynamic_pointer_cast that could directly convert the Smart Pointer object, and both of these methods would be much safer than the manual path using the original pointer.
I used the aliasing shared_ptr constructor, which is used in my small library:
http://code.google.com/p/infectorpp/ (just my simple IoC container)
The fact is, since I need shared_ptr of a known type, which should be returned from a polymorphic class (which does not know the type). I could not implicitly convert shared_ptr to the type I need.
In the InfectorHelpers.hpp file "(line 72-99), you can see what is in action for type IAnyShared.
The merge constructor creates shared_ptr, which does not delete the pointers that they actually point to, but they still increment the reference counter to the source object and can be extremely useful.
Basically, you can create a pointer to anything using the anti-aliasing constructor and threaten it as a reference counter.
//my class std::shared_ptr<T> ist; int a; //dummy variable. I need its adress virtual std::shared_ptr<int> getReferenceCounter(){ return std::shared_ptr<int>(ist,&a); //not intended for dereferencing } virtual void* getPtr(); //return raw pointer to T we now have both a โreference counterโ and a pointer to a T value, enough data to create something with an alias constructor
std::shared_ptr<T> aPtr( any->getReferenceCounter(), //share same ref counter static_cast<T*>(any->getPtr()) ); //potentially unsafe cast! I do not pretend to have invented this use for the alias constructor, but I have never seen anyone else do the same. If you know if this dirty code works, yes.