Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Smart Pointers and Exception handling

I have looked over the internet and this thread looking for a complete answer of this situation I am facing. I have read that throwing smart pointers to objects is not very clever. I just want to understand why is this happening. I will explain the situation. Let's imagine this simple hierarchy:

class Foo 
{ 
public: virtual ~Foo() {} 
}; 

typedef tr1::shared_ptr<Foo> SPFoo; 

class FooInherited: public Foo { }; 

typedef tr1::shared_ptr<FooInherited> SPFooInherited; 

And let's check this test code:

int main(int argc, char** argv) 
{ 
  try 
  { 
    throw FooInherited(); 
  } 
  catch(const Foo& f) 
  { 
    cout << "Foo& caught!" << endl; 
  } 
  try 
  { 
    throw SPFooInherited(new FooInherited()); 
  } 
  catch(const SPFoo& f) 
  { 
    cout << "SPFoo& caught!" << endl; 
  } 
  return 0; 
} 

Everything compiles but in runtime the second try-catch won't be executed. Can someone explain me why? Specially if lines of code like this work perfectly fine in runtime.

void function(const SPFoo& f) 
{ 
} 

... 

SPFooInherited fi(new FooInherited()); 
function(fi);

I do understand that the problem is that SPFooInherited does not inherit from SPFoo (even though FooInherited inherits from Foo), but It deeply would like to know what is the compiler/RTE doing differently from the function call example when catching an exception not to be able to solve de situation. Is it because the catch parameter is not the same as a function call parameter? Why Foo& works and SPFoo doesn't?

Thank you very much in advance.

Regards, Iker.

like image 788
Iker Jamardo Avatar asked Sep 05 '11 14:09

Iker Jamardo


People also ask

What are smart pointers used for?

Smart pointers are used to make sure that an object is deleted if it is no longer used (referenced). The unique_ptr<> template holds a pointer to an object and deletes this object when the unique_ptr<> object is deleted.

What do smart pointers prevent?

Smart pointers try to prevent memory leaks by making the resource deallocation automatic: when the pointer to an object (or the last in a series of pointers) is destroyed, for example because it goes out of scope, the pointed object is destroyed too. Save this answer.

What is the difference between smart pointers and regular pointers?

The main difference is that reference counted smart pointers can be copied (and used in std:: containers) while scoped_ptr cannot. Non reference counted pointers have almost no overhead or no overhead at all.

What are the different types of smart pointers?

C++ libraries provide implementations of smart pointers in following types: auto_ptr. unique_ptr. shared_ptr.


2 Answers

As you said in your question, SPFooInherited is not a subclass of SPFoo. This means that catch(SPFoo const&) will not catch instances of SPFooInherited. On the other hand, FooInherited is inherited from Foo, and so catch(Foo const&) will catch instances of FooInherited.

To understand this you do not need any special understanding of the compiler or run-time-environment. It is simply a part of the language.

The reason that the call to the function works is that tr1::shared_ptr has a templated non-explicit constructor that allows an implicit conversion to take place at function call sites.

That is: tr1::shared_ptr has the following constructor:

//Note the lack of explicit
template<class Y> shared_ptr(shared_ptr<Y> const & r);

This allows a shared_ptr to be constructed from a different shared pointer type. The implementation of this constructor relys on the implicit conversion from FooInherited* to Foo* to actually store the pointer in the SPFooInherited into the SPFoo. If this implicit conversion does not exist then the code will not compile, and so unsafe conversions between shared_ptrs to unrelated types will not occur.

The fundamental difference between the function call and the catch is that implicit conversions will occur in the initialization of function arguments, but a catch can only match a single type (FooInherited is-a Foo, so it will match).

like image 76
Mankarse Avatar answered Sep 30 '22 08:09

Mankarse


Because SPFoo is not a subclass of SPFooInherited. catch blocks will only catch things that are in their catch list, or a public child class of what's in their catch list. FooInherited does inhertit from Foo, so catching a Foo will also let you catch a FooInherited. SPFoo and SPFooInherited are completely different and unrelated classes.

like image 25
Seth Carnegie Avatar answered Sep 30 '22 08:09

Seth Carnegie