views:

63

answers:

1

I am using C++. C++0x using Visual Studio 2010 to be correct.

Suppose I have a class Z. To make it safer in my application to work with pointers to this class, I can consistently use smart pointers (shared pointer, weak pointer).

Now this class Z inherits from a class X. Some parts of my application will work with pointers to class X, others will work with pointers to class Z.

  • Can I still use smart pointers?
  • Do shared pointers still work if I have some that refer to X and others that refer to Z? Is it guaranteed that the destruction of the last shared pointer to the instance (regardless of whether it is std::shared_ptr<X> or std::shared_ptr<Z>) deletes the instance? Am I sure that if I delete std::shared_ptr<X>, that the instance is kept as long as there is another std::shared_ptr<Y>?

Now suppose that I use multiple inheritance, where Z inherits from classes X and Y. Some parts of my application will work with std::shared_ptr<X>, others with std::shared_ptr<Y> and others with std::shared_ptr<Z>.

  • Can I still use shared pointers this way?
  • Is it still guaranteed that only the last smart pointer (regardless of whether it points to X, Y or Z) deletes the instance?

By the way, how can I safely cast one smart pointer to another, e.g. cast std::shared_ptr<Z> to std::shared_ptr<X>? Does this work? Is this allowed?

Notice that I explicitly refer to non-intrusive pointers (as the new std::shared_ptr and std::weak_ptr in C++0x). When using intrusive pointers (like in Boost), it probably works since the instance itself is responsible for keeping the counter.

+4  A: 

Yes this is supported by the standard, §20.9.11.2.10 [util.smartptr.shared.cast].

The utils you need are:

  • std::static_pointer_cast<>()
  • std::dynamic_pointer_cast<>()

They have the same semantics as their C++03 counter parts static_cast<>() and dynamic_cast<>(). The one difference being that they only work on std::shared_ptrs. And just to verbose, they do what you expect and correctly share the reference count between the original and newly cast shared_ptrs.

struct X { virtual ~X(){} };
struct Y : public X {};
struct Z : public X {};

int main()
{
   {
      //C++03
      X* x = new Z;
      Z* z = dynamic_cast<Z*>(x);
      assert(z);
      x = new Y;
      z = dynamic_cast<Z*>(x);
      assert(!z);
      z = static_cast<Z*>(x);
      assert(z); //EVIL!!!
   }

   {
      //C++0x
      std::shared_ptr<X> x{new Z};
      std::shared_ptr<Z> z{std::dynamic_pointer_cast<Z>(x)};
      assert(z);
      x = std::make_shared<Y>();
      z = std::dynamic_pointer_cast<Z>(x);
      assert(!z);
      z = std::static_pointer_cast<Z>(x);
      assert(z); //EVIL!!!

      // reference counts work as expected.
      std::shared_ptr<Y> y{std::static_pointer_cast<Y>(x)};
      assert(y);

      std::weak_ptr<Y> w{y};
      assert(w.expired());

      y.reset();
      assert(w.expired());

      x.reset();
      assert(!w.expired());      
   }
   {
      //s'more nice shared_ptr features
      auto z = std::make_shared<X>();
      std::shared_ptr<X> x{z};
      assert( z == x );
      x = z; //assignment also works.
   }
}
caspin
Wow never heard of this... O__o No reference to this in any resource I could find on C++0x other than the (indigest) draft...
Klaim
I didn't know for sure the casts where there till I looked it up. I did however strongly suspect they were there as they were part of the original Boost.Smartptr library.
caspin
Please get rid of "std::" in front of the built-in cast operators. Also, a dynamic cast of this type requires polymorphic classes. Your example classes are not polymorphic.
sellibitze
Fixed it, Maybe SO should have an option to filter code samples through edge online for validation.
caspin