Constructor Exceptions in C++, C#, and Java

I just received the following question, whose answer is the same in C++, C#, and Java.

Question: In the following code, why isn’t the destructor/disposer ever called to clean up the Widget when the constructor emits an exception? You can entertain this question in your mainstream language of choice:

// C++ (an edited version of the original code
// that the reader emailed me)
class Gadget {
   Widget* w;

public:
   Gadget() {
     w = new Widget();
     throw new exception();
     // … or some API call might throw
   };

   ~Gadget() {
      if( w != nullptr ) delete w;
   }
};

// C# (equivalent)
class Gadget : IDisposable {
   private Widget w;

   public Gadget() {
     w = new Widget();
     throw new Exception();
     // … or some API call might throw
   };

   public void Dispose() {
     // … eliding other mechanics, eventually calls:
     if( w != null ) w.Dispose();
     // or just “w = null;” if Widget isn’t IDisposable
   }
};

// Java (equivalent)
class Gadget {
   private Widget w;

   public Gadget() {
     w = new Widget();
     throw new Exception();
     // … or some API call might throw
   };

   public void dispose() {
     if( w != null ) w.dispose();
     // or just “w = null;” if Widget isn’t disposable

   }
};

Interestingly, we can answer this even without knowing the calling code… but there is typical calling code that is similar in all three languages that reinforces the answer.

Construction and Lifetime

The fundamental principles behind the answer is the same in C++, C#, and Java:

  1. A constructor conceptually turns a suitably sized chunk of raw memory into an object that obeys its invariants. An object’s lifetime doesn’t begin until its constructor completes successfully. If a constructor ends by throwing an exception, that means it never finished creating the object and setting up its invariants — and at the point the exceptional constructor exits, the object not only doesn’t exist, but never existed.
  2. A destructor/disposer conceptually turns an object back into raw memory. Therefore, just like all other nonprivate methods, destructors/disposers assume as a precondition that “this” object is actually a valid object and that its invariants hold. Hence, destructors/disposers only run on successfully constructed objects.

I’ve covered some of these concepts and consequences before in GotW #66, “Constructor Failures,” which appeared in updated and expanded form as Items 17 and 18 of More Exceptional C++.

In particular, if Gadget’s constructor throws, it means that the Gadget object wasn’t created and never existed. So there’s nothing to destroy or dispose: The destructor/disposer not only isn’t needed to run, but it can’t run because it doesn’t have a valid object to run against.

Incidentally, it also means that the Gadget constructor isn’t exception-safe, because it and only it can clean up resources it might leak. In the C++ version, the usual simple way to write the code correctly is to change the w member’s type from Widget* to shared_ptr<Widget> or an equivalent smart pointer type that owns the object. But let’s leave that aside for now to explore the more general issue.

A Look At the Calling Code

Next, let’s see how these semantics are actually enforced, whether by language rules or by convention, on the calling side in each language. Here are the major idiomatic ways in each language to use an Gadget object in an exception-safe way:

// C++ caller

{
  Gadget myGadget;
  // do something with myGadget
}

// C# caller

using( Gadget myGadget = new Gadget() )
{
  // do something with myGadget
}

// Java caller

Gadget myGadget = new Gadget();

try {
  // do something with myGadget
}
finally {
  myGadget.dispose();
}

Consider the two cases where an exception can occur:

  • What if an exception is thrown while using myGadget — that is, during “do something with myGadget”? In all cases, we know that myGadget’s destructor/dispose method is guaranteed to be called.
  • But what if an exception is thrown while constructing myGadget? Now in all cases the answer is that the destructor/dispose method is guaranteed not to be called.

Put another way, we can say for all cases: The destructor/dispose is guaranteed to be run if and only if the constructor completed successfully.

Another Look At the Destructor/Dispose Code

Finally, let’s return to each key line of code one more time:

// C++
      if( w != nullptr ) delete w;
// C#
     if( w != null ) w.Dispose();
// Java
     if( w != null ) w.dispose();

The motivation for the nullness tests in the original example was to clean up partly-constructed objects. That motivation is suspect in principle — it means the constructors aren’t exception-safe because only they can clean up after themselves — and as we’ve seen it’s flawed in practice because the destructors/disposers won’t ever run on the code paths that the original motivation cared about. So we don’t need the nullness tests for that reason, although you might still have nullness tests in destructors/disposers to handle ‘optional’ parts of an object where a valid object might hold a null pointer or reference member during its lifetime.

In this particular example, we can observe that the nullness tests are actually unnecessary, because w will always be non-null if the object was constructed successfully. There is no (legitimate) way that you can call the destructor/disposer (Furthermore, C++ developers will know that the test is unnecessary for a second reason: Delete is a no-op if the pointer passed to it is null, so there’s never a need to check for that special case.)

Conclusion

When it comes to object lifetimes, all OO languages are more alike than different. Object and resource lifetime matters, whether or not you have a managed language, garbage collection (finalizers are not destructors/disposers!), templates, generics, or any other fancy bell or whistle layered on top of the basic humble class.

The same basic issues arise everywhere… the code you write to deal with them is just spelled using different language features and/or idioms in the different languages, that’s all. We can have lively discussions about which language offers the easiest/best/greenest/lowest-carbon-footprint way to express how we want to deal with a particular aspect of object construction, lifetime, and teardown, but those concerns are general and fundamental no matter which favorite language you’re using to write your code this week.

35 thoughts on “Constructor Exceptions in C++, C#, and Java

  1. Here’s an “exception” for you: Delphi.

    When an exception is thrown in a Delphi constructor, the destructor is automatically called and the exception rethrown.

    This works especially well in Delphi because of two object construction conventions:

    * The memory for an object’s fields is always zeroed out before the constructor is entered (TObject.InitInstance)
    * The normal way to free an object in Delphi is to call the nonvirtual instance method TObject.Free, which will only invoke the destructor /if “Self” is not *nil*/.

    Thus, it is safe to have a destructor that is a list of calls to ‘.Free’ on fields referring to owned objects, even though many of those objects might not have been created yet when and if an exception gets thrown in the constructor.

    Getting the same semantic behaviour in other languages that are less like Delphi can be somewhat painful, because exceptions thrown in constructors need special handling – you can’t rely on destructor cleanup.

  2. Thanks Barry because I was just exploring the varying same topic in Delphi.W32. Not sure if I have done something wrong. When I deliberately throw an exception in the constructor, the class’ destructor does not seem to be called. My trace never fired!

    With respect to the acceptable practice of calling embedded object’s Free() in the destructor, in C++ all fully constructor embedded objects are automatically destroyed; only partially constructed aren’t.

    Hence, as far as destruction is concerned, there isn’t much difference between Delphi and C++.

  3. Thank you Herb.
    Can you explain what happen if the constructor of a derived class throw an exception, after the base subobject has been constructed?
    Does the Berived object never exist? (probably it doesn’t)
    And what about the Base? (probably it does)

    (I’m a C++ programmer)

  4. Jack:

    You probably forgot to include override on your destructor (which has to be called Destroy). Since it’s called by the framework then you need this for it to be called. But exceptions raised in a Delphi constructor do indeed result in the Destroy running.

    The documentation say:

    “If an exception is raised during execution of a constructor that was invoked on a class reference, the Destroy destructor is automatically called to destroy the unfinished object.”

    You can also take look at the implementation of _ClassCreate in System.pas if you really don’t believe that Delphi behaves in this way.

    Actually this behaviour is great for the majority of resources that are created. You have to be a little careful with non-native resources (e.g. system handles, windows etc.) but otherwise it means that exceptions in constructors can be dealt with easily.

  5. Hi ugasoft!
    In that case Base is destructed no matter if the Derived object is a normal object or a pointer.

  6. “I’ve covered some of these concepts and consequences before in GotW #66, “Constructor Failures,” which appeared in updated and expanded form as Items 17 and 18 of More Exceptional C++.” Herb Sutter

    It’s also covered in The C++ Programming Language/Special Edition/ by Stroustrup par 14.4.1

  7. 15.2.2 in the C++ Language Specification says it clear: an object that is partially constructed will have destructors executed for all of its fully constructed subobjects.

    But what about this example, which is like the OO “Hello, world!” escorted by the Goodbye message:

    // …

    class Base {
    public:
    Base() { cout << “Hello from Base()” << endl; }
    ~Base() { cout << “Goodbye from ~Base()” << endl; }
    };

    class Derived : public Base {
    public:
    Derived() { cout << “Hello from Derived()” << endl; }
    ~Derived() { cout << “Nobody loves me” << endl; }
    };

    int main()
    {
    Base *pbase = new Derived();
    delete pbase;
    }

    After the execution we’ll have:

    Hello from Base2()
    Hello from Derived2()
    Goodbye from ~Base2()

    Don’t we have a fully constructed object of type Derived?

    In the last paragraph of the section “A Look At the Calling Code” Mr. Sutter said (at a general level): “[…] we can say for all cases: The destructor/dispose is guaranteed to be run if and only if the constructor completed successfully.”
    What if the Widget is derived from Gadget?
    Then in the first case from the quoted section, if myGadget is dynamically allocated by new Widget(), the ~Widget() will not be called if the ~Gadget() isn’t virtual.
    In the second case, if the exception is thrown from Widget(), the destructor for Gadget is still called.

    So, the successfully completeness of an object should be completed (mmm) with the storage location type (stack or heap) – considering that the storage is allocated before the object construction start – and with the proper use of the polymorphism rules.

    Excuse my language. My English language.

  8. > C++ […]
    > throw new exception();

    You didn’t really mean to throw a pointer here, did you? ;)

  9. Laurentiu: your destructor in Base is not virtual. Thus the delete call will call Base::~Base() instead of Derived::~Derived()

  10. I think it’s useful to point out that in C++, a common solution automatic destruction of members is to introduce a new base class, and then let the base manage object lifetimes. This is done in several parts of the GNU STL implementation (such as std::vector). I’m pretty sure there’s an example of this in “[More] Exceptional C++” as well.

  11. Hi Herb,

    I’m not quiet sure that it’s always true to say “Delete is a no-op if the pointer passed to it is null,” isn’t it usually getting access violation with VS2005/VC8 ?

  12. Hi Herb,

    Or I suspect that access violation is actually coming from deleting a null memory address of the pointer itself, not a null pointer?

  13. Hi Herb,

    Sorry for bothering, please %s/quiet/quite/g in my recent comments, thank you

  14. Herb,

    The deck was stacked for the C++ example. A smart pointer would solve this problem (performing the cleanup that the original author intended):

    // C++ w RAII
    class Gadget {
    std::auto_ptr w;

    public:
    Gadget() {
    w.reset(new Widget());
    throw new exception();
    // … or some API call might throw
    };

    ~Gadget() {
    // nothing to do, auto_ptr will always delete
    // the widget, even if the destructor isn’t invoked.
    }
    };

    // C# (equivalent)
    class Gadget : IDisposable {
    private Widget w;

    public Gadget() {
    bool complete = false;
    try{
    w = new Widget();
    throw new Exception();
    // … or some API call might throw
    complete=true;
    }finally{

    if(!complete)
    {
    // manually invoke cleanup on base class
    // and on each member object
    if(w != null) w.Dispose();
    }
    }
    };

    public void Dispose() {
    // … eliding other mechanics, eventually calls:
    if( w != null ) w.Dispose();
    // or just “w = null;” if Widget isn’t IDisposable
    }
    };

    #aaron

  15. Note: in previous post, “auto_ptr w;” should have read “auto_ptr LT Widget GT w;”, where LT and GT are the less-than and greater-than symbols respectively (comment form bug).

  16. Augustinus,
    deleting a null pointer should only cause an access violation in VS6.

    VS7/8/9 all perform the correct behaviour as Herb stated.

  17. Hi Herb,

    There’s a little exception to the rule. It’s the operator new [] ;-) For example, let’s take into consideration the following code:

    #include

    template void unused(const T) {}

    class Foo
    {
    public:
    static int nctors;
    static int ndtors;

    Foo()
    {
    if(maxn <= Foo::n++)
    {
    throw 3;
    }

    std::cout<<__PRETTY_FUNCTION__<<“: Succeeded\n”;

    ++Foo::nctors;
    }

    ~Foo()
    {
    std::cout<<__PRETTY_FUNCTION__<<“: Called\n”;

    ++Foo::ndtors;
    }
    private:
    static int n;
    static const int maxn = 210;
    };

    int Foo::n = 0;
    int Foo::nctors = 0;
    int Foo::ndtors = 0;

    class Bar
    {
    public:
    // We’ll certanly call destructors for constructed objects…
    Bar()
    : foo_(new Foo[300])
    {
    std::cout<<__PRETTY_FUNCTION__<<“: Succeeded\n”;
    }

    ~Bar()
    {
    std::cout<<__PRETTY_FUNCTION__<<“: Called\n”;
    }
    private:
    Foo* foo_;
    };

    int main()
    {
    try
    {
    Bar bar;

    unused(bar);
    }
    catch(…) {}

    std::cout<<“Foo constructors called: “<<Foo::nctors<<std::endl;
    std::cout<<“Foo destructors called: “<<Foo::ndtors<<std::endl;
    }

    I’ll throw away all the blah succeeded/called and leave only the output of the last two lines of main():

    Foo constructors called: 210
    Foo destructors called: 210

    Let’s examine the code. The Bar did never exist just like poor Parrot ;-) But Foo::~Foo was called (a bit like paradox). I guess you should point this out in your Exceptional C++ books. It’s quite possible that a novice programmer will try to write something like that:

    Bar()
    try
    : foo_(new Foo[300])
    {
    std::cout<<__PRETTY_FUNCTION__<<“: Succeeded\n”;
    }
    catch(…)
    {
    delete foo_; ///< Oh no! Gush, my compiler gone crazy 8-)
    }

    Regards,
    Oleksii Skidan

  18. Herb,

    Thanks for the great article, especially comparison to C# and Java. I’ve learned a lot.

    However, it’s still unclear to me what consequences are expected in C# and Java from not calling disposer on Widget when Gadgets construction does not complete.

    In C++, the situation is clear: memory allocated for Widget leaks. What happen with Widget in C# and Java? Isn’t it collected at some point?

  19. One differense that has bitten me in C# here is that in C++ all member and base object whose constructor has run will have its destructor run . But that will not be the case for a C# using statement.

  20. what’s with using dispose for C#? Dispose is not the destructor (C# has the same ~ syntax as C++ for destructors). The dispose method will never get called by the GC. user code has to explicitly call it like you did with the using syntax. GC calls the C# destructor (aka finalizer) when cleaning up the object which DOES get called even when the constructor throws an exception.

    dispose was meant for unmanaged resources which have to be manually released as the GC does not know about them.

    i thought i had a pretty good handle on finalize/dispose but i’m confused now…

  21. If call the constructor which has an exception handling, how would I inform the caller about the exception? Should I then include try catch in caller? And what type of exceptions I should be prepared to deal with?

    The intention is to create an Object which will analyze on its own whether data source exists and if it is not, fails and informs caller about this.

    Lets say:
    class FileProcessing{
    public FileProcessing(string fName)
    {
    try{
    StreamReader sr = new StreamReader(fName);
    }
    catch(FileNotFoundException fnfex)
    {
    }

    }
    public ReplaceOldNames()
    {
    }
    }

    Should I generate custom exception? Or it is a way to pass FileNotFoundException ?

    Thank you

  22. Very interesting post!

    I was actually searching for something else but i stopped a moment to read your point.

    Julian

  23. Hmmm very interesting post and lot of healthy information.
    I was looking for what to do in we got exception in constructor or destructor?

    ;) actually this questions was asked in my today interview that time i didn’t know at all.

    Now after reading the post……… i got good info.
    Thanks you all…….

  24. A colleague of mine uses C# these days and thought along the same lines you (and I) do. The problem he has is that something like this, in C#, prints out «Dead!» (same effect with IDisposable and Dispose(), BTW). Maybe I’m missing something, but my understanding was that C#’s finalizer (~X() in this case) would not be called, X’s constructor having never completed normally, but the fact is: it is called and it does print… Any thoughts?

    using System;

    namespace Whatever
    {
    class Program
    {
    public class X
    {
    public X()
    {
    throw new Exception();
    }
    ~X()
    {
    Console.WriteLine(“Dead!”);
    }
    }
    static void Main(string[] args)
    {
    try
    {
    X x = new X();
    }
    catch (Exception)
    {
    }
    }
    }
    }

  25. This article is incorrect. Finalizers in C# WILL be called even if an exception is thrown in the constructor.

  26. Whoa, there. For Java it seems that finalizers do run if the constructor throws an exception.

    The wording in the JLS for object creation says that, after allocation, the initialization either “completes abruptly” or “completes normally”. Then the section on finalization says:

    “The completion of an object’s constructor happens-before (§17.4.5) the execution of its finalize method (in the formal sense of happens-before).”

    And that’s all it says. The word “completion” is not qualified, so I could infer that finalizers always run after any completion, including the “abrupt completion” when a constructor throws an exception.

    It’s a little sloppy because the section on creation makes a careful distinction between field initialization and the constructors. (Because of that I could also infer that if a field initialization fails then maybe the finalizer isn’t run?)

    References: Java Language Specification (3rd ed), sections 12.5 and 12.6

Comments are closed.