The case of C++
In C++ constructors are expected to succeed. The only way for a constructor to fail is to raise an exception.
Bjarne Stroustrup confirms in his book "The design and evolution of C++" that this is one of the most important aspect of exceptions (Chapter 16.5.1: Errors in constructors), as you rightly pointed out in your question.
Now imagine for a second that a constructor could fail without exceptions...
The pointer initialisation Object *o = new Object;
could work with this semantic without problem with a nullptr
. In fact, it is possible to get this semantic if the failure is caused by an allocation issue with nothrow
.
But how could you handle the following cases:
- Construction of local (value) object:
Object o;
invokes for example a default constructor. If failed construction would be possible, you or the compiler would have to check for a void object in all subsequent uses of o
. In most cases this would be a performance overhead that is justified only by some exceptional cases, which is not the design philosophy of C++
- Construction of a class member : for example
class X { public: Object o; };
. If construction of o
would fail, in this simple example you could simply imagine to say that the class X
object construction fails as well. But how should it work if class X would have several different members, some of them with a successful construction, and some of them with a failed object ? And what if there would be some other pointer members where the compiler cannot determine if the pointed object should be destroyed or not in case of a partially failed construction of X
?
- Construction of a derived class: what to do if a base class object could be successfully constructed, but the derived class object not: should the bbase class object be returned ? Or should it be destroyed ?
- I don't mention multiple inheritance or virtual inheritance which have similar problems.
If C++ would allow constructors to fail, there would be a lot of unsolved semantic issues, or a lot of overhead that is useless most of the time. This explains the current design option: handle exceptional circumstances exceptionally.
By the way, Object o = new Object();
is not valid in C++.
Code design issue ?
If you feel you have the need for a constructor that is expected to fail as a normal behavior, there is certainly a design issue.
May be you should then consider to use an object with a special fail
state. You would then consider again that construction is always successful, but that the state of the object might not be the one that is expected. You could then check whenever needed if the state of the object is ok or not.
Java and C# cases
Java and C# also expect the constructor to succeed or to raise an exception. The reasons are very similar to those mentioned for C++. Although case 1 would not be applicable because objects are managed by reference, and case 4 not relevant because these languages do not support MI, the case 2 and 3 would cause semantic issues in case of partially created objects.
If the language was to allow constructor failure without exception, it would have to decide how to handle partially successful construction (either keep the correct member objects and let the other be nil, or destroy constructed members and return nil). But the chosen semantic might not be the correct one in every case. Exception handling allows more flexibility in this regard.
As a solution to the design smell, in addition to the special fail state already mentioned for C++, you could also easily use a factory or a builder that could return nil, for example if the construction parameter are invalid.
return void
.