3

I have my smart pointer implementation as bellow which is NOT deallocating memory at exceptions ..

template <class T>
class SMARTPOINTER
{
public:
   SMARTPOINTER(T* pointee) : SMART_POINTEE(pointee) {
    cout <<"\n Inside class SMARTPOINTER CONSTURCTOR \n";
   }

   ~SMARTPOINTER() {
     cout <<"\n Inside class SMARTPOINTER DESTRUCTOR \n";
      delete SMART_POINTEE;
   }

   T& operator*() const
   {
      cout <<"\n Inside class SMARTPOINTER operator* \n";
      return *SMART_POINTEE;
   }

   T* operator->() const
   {
      cout <<"\n Inside class SMARTPOINTER operator->()  \n";
      return SMART_POINTEE;
   }

private:
   T* SMART_POINTEE;

};

class Widget
{
public:

  Widget() {
      cout <<"\n Inside Widget CONSTRUCTOR \n";
  }

   void Fun() { 
     cout <<"\n Inside Widget::Fun() \n";
   }

  ~Widget() {
      cout <<"\n Inside Widget DESTRUCTOR \n";
  }

};

class THROWME{

};

int main() {

SMARTPOINTER<Widget> sp(new Widget);
sp->Fun();
throw new THROWME;
(*sp).Fun();

return 0 ;
}

I find that the output is

Inside Widget CONSTRUCTOR 

 Inside class SMARTPOINTER CONSTURCTOR 

 Inside class SMARTPOINTER operator->()  

 Inside Widget::Fun() 
uncaught exception of type THROWME*
Aborted.

As far as I know Smart pointers are supposed to help me in such cases!! I do not find destruction of Widget getting called via smart pointer .

So I must be missing some implementation here .

EDIT AFTER COMMENTS READ

With try catch i got my result . But i still dont know if its right approach change in code

  int main() {
        try {
        SMARTPOINTER<Widget> sp(new Widget);
        sp->Fun();
        THROWME tm;
        throw tm;
        (*sp).Fun();
        }
        catch(...) {
          cout <<"\n **SOME EXCEPTION CAUGHT**  \n";
        }
        return 0 ;
        }

result

 Inside Widget CONSTRUCTOR 

 Inside class SMARTPOINTER CONSTURCTOR 

 Inside class SMARTPOINTER operator->()  

 Inside Widget::Fun() 

 Inside class SMARTPOINTER DESTRUCTOR 

 Inside Widget DESTRUCTOR 

 **SOME EXCEPTION CAUGHT**
MAG
  • 2,841
  • 6
  • 27
  • 47
  • 1
    I'm not 100%, but I think you need to CATCH the exception to get the destructor to be called. Since you don't, it's not happening, because the "we couldn't find where to go back to" error handler kicks in first. – Mats Petersson Jun 01 '13 at 08:37
  • if i had to catch exceptions and handle stuff .. i would rather not use smart pointer .. I think there is something else missing .. – MAG Jun 01 '13 at 08:39
  • 1
    You shouldn't throw Exceptions as Pointers (where do you `delete` them?). Just do `throw THROWME();` – stefan Jun 01 '13 at 08:40
  • I dont agree its duplicate .. i want to know whats missing in my smart pointer implementation that will solve this without me to handle exception – MAG Jun 01 '13 at 08:41
  • And what do you EXPECT to happen if you throw an exception that isn't caught? The program will exit anyway. So the only time it makes a difference is if you are doing something in the destructor that affects something external (e.g. writing/flushing a file in the destructor). If so, you should be using at least a try/catch in main. – Mats Petersson Jun 01 '13 at 08:43
  • It is basically the same thing, as for your widget to be destroyed, the destructor of your smart pointer must be called. Another very similar question: [Are destructors called after a throw in C++?](http://stackoverflow.com/questions/8311457/are-destructors-called-after-a-throw-in-c) – Joe Jun 01 '13 at 08:44
  • 1
    @MAG: You can disagree all you like, but until the C++ specification changes such that you don't need a `try`/`catch` block to know where to go back to, the runtime will still do this. – Mats Petersson Jun 01 '13 at 08:44
  • @MatsPetersson A try/catch in main is terrible for debugging, I would not recommend it – Joe Jun 01 '13 at 08:44
  • @joe, well, a `try`/`catch` somewhere for sure. The point is that you need one. Your answer says so too. – Mats Petersson Jun 01 '13 at 08:46
  • @MatsPetersson Only if it is absolutely necessary to call the destructor in all cases (as in your file flushing example). – Joe Jun 01 '13 at 08:49
  • 1
    @Joe: Agreed. But the original poster asked "well, if I have to try/catch everywhere to get the destructor called" - it seems like OP wants to have the destructor called, to me. As always, there is the possibility of "ignoring errors and just exiting" - this works quite well in most of my code ;) – Mats Petersson Jun 01 '13 at 08:51

2 Answers2

4

The destructor is not being called as the unhandled exception THROWME causes std::terminate to be called. See also this question, specifically the first quotation in the accepted answer:

C++11 15.2 Constructors and destructors [except.ctor]

1 As control passes from a throw-expression to a handler, destructors are invoked for all automatic objects constructed since the try block was entered. The automatic objects are destroyed in the reverse order of the completion of their construction.

As you have no try block to handle the exception, no destructor is called.

Community
  • 1
  • 1
Joe
  • 6,497
  • 4
  • 29
  • 55
4

Calling of the destructor is part of stack unwinding, which is done when the exception "bubbles up" the call stack... except when the exception is unhandled. In that case, whether or not the stack is unwound is implementation-defined:

If no matching handler is found in a program, the function terminate() (except.terminate) is called. Whether or not the stack is unwound before calling terminate() is implementation-defined.

To handle this more gracefully, you could use a function try block:

int main()
try {
  // main body
} catch (...) {
  std::cerr << "Unhandled exception\n";
  std::terminate();
}

... although this will swallow the exception and make it hard to debug.

Thomas
  • 174,939
  • 50
  • 355
  • 478