Is It Ever Not Safe to Throw an Exception in a Constructor

Is it ever not safe to throw an exception in a constructor?

Throwing exceptions from a constructor is a good thing. When something fails in a constructor, you have two options:

  • Maintain a "zombie" state, where the class exists but does nothing, or
  • Throw an exception.

And maintaining zombie classes can be quite a hassle, when the real answer should have been, "this failed, now what?".

According to the Standard at 3.6.2.4:

If construction or destruction of a non-local static object ends in throwing an uncaught exception, the result is to call terminate (18.6.3.3).

Where terminate refers to std::terminate.


Concerning your example, no. This is because you aren't using RAII concepts. When an exception is thrown, the stack will be unwound, which means all objects get their destructor's called as the code gets to the closest corresponding catch clause.

A pointer doesn't have a destructor. Let's make a simple test case:

#include <string>

int main(void)
{
try
{
std::string str = "Blah.";
int *pi = new int;

throw;

delete pi; // cannot be reached
}
catch(...)
{
}
}

Here, str will allocate memory, and copy "Blah." into it, and pi will be initialized to point to an integer in memory.

When an exception is thrown, stack-unwinding begins. It will first "call" the pointer's destructor (do nothing), then str's destructor, which will free the memory that was allocated to it.

If you use RAII concepts, you'd use a smart pointer:

#include <memory>
#include <string>

int main(void)
{
try
{
std::string s = "Blah.";
std::auto_ptr<int> pi(new int);

throw;

// no need to manually delete.
}
catch(...)
{
}
}

Here, pi's destructor will call delete and no memory will be leaked. This is why you should always wrap your pointers, and is the same reason we use std::vector rather than manually allocating, resizing, and freeing pointers. (Cleanliness and Safety)

Edit

I forgot to mention. You asked this:

I think I want to put an autoptr around P and call release on the autoptr after dostuff to prevent a memory leak, would that be correct?

I didn't state it explicitly, and only implied it above, but the answer is no. All you have to do is place it inside of auto_ptr and when the time comes, it will be deleted automatically. Releasing it manually defeats the purpose of placing it in a container in the first place.

I would also suggest you look at more advanced smart pointers, such as those in boost. An extraordinarily popular one is shared_ptr, which is reference counted, making it suitable for storage in containers and being copied around. (Unlike auto_ptr. Do not use auto_ptr in containers!)

When is it right for a constructor to throw an exception?

The constructor's job is to bring the object into a usable state. There are basically two schools of thought on this.

One group favors two-stage construction. The constructor merely brings the object into a sleeper state in which it refuses to do any work. There's an additional function that does the actual initialization.

I've never understood the reasoning behind this approach. I'm firmly in the group that supports one-stage construction, where the object is fully initialized and usable after construction.

One-stage constructors should throw if they fail to fully initialize the object. If the object cannot be initialized, it must not be allowed to exist, so the constructor must throw.

What happens if a constructor throws an exception?

No, throwing an exception is the best way to signal an error during object construction. (Since there's no return value, there's no other way, other than constructing a headless object, which is bad style in C++.)

From the man himself, Bjarne Stroustrup: http://www.stroustrup.com/bs_faq2.html#ctor-exceptions

(If you are working in a project where exceptions aren't allowed, then you have to make the constructor infallible, and move any logic that could fail into a factory function that has the possibility of returning an error.)

Re: "But my destructor was not called"

Indeed.
In C++ the lifetime of an object is said to begin when the constructor runs to completion. And it ends right when the destructor is called. If the ctor throws, then the dtor is not called.

(But dtors of any member variable objects, whose ctors already ran to completion before this ctor ran, are called.)

You should consult the standard, or a good textbook for more details, esp. related to what happens when inheritance is involved. As a general rule of thumb, destructors are called in the reverse order of construction.

Your question about why "~B" was not called in your specific code, it's because you do not catch the exception in main. If you change your code so that main catches the exception, then "~B()" will be called. But, when an exception is thrown which has no catch, the implementation is free to terminate the program without calling destructors or destroying statically initialized objects.

Reference in C++11 standard (emphasis mine):

15.5.1 The std::terminate() function [except.terminate]

1
In some situations exception handling must be abandoned for less subtle error handling techniques.

...

2
In such cases, std::terminate() is called (18.8.3). In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called.

As a side note, generally speaking with gcc and clang, ~B will be called anyways in your example program, while with MSVC, ~B will not be called. Exception handling is complex and the standard allows that compiler writers can experiment with and choose what implementation that they think is best in this regard, but they cannot choose to give undefined behavior.

If it's really important for your program that the destructors are called even in this case, then you should make sure to catch exceptions in main so that your code will be portable (work the same on all conforming compilers). For example:

int main() {
try {
A a;
} catch (...) {}
}

This way, compilers like MSVC will be obligated to call the destructor of B before exiting.

Java: Exception in constructors: Problematic or not?

There is nothing wrong with exceptions in constructors (or factory methods, either way is fine). sometimes, doing too much work in a constructor can be a poor design, and may make sense to move to a factory method.

the only thing that point 2 proves is that exceptions in constructors are not an adequate security mechanism for protecting a class from evil usage. however, there are any number of ways to subvert such a design, which is why the only way to truly run secure code in java is running with a SecurityManager. so point 2 is just a straw man argument.

Is it okay for constructors to throw runtime exceptions?

Yes, this is inevitable in many constructors anyway when they call other methods since there is always a possibility that they will already throw unchecked exceptions.

Throwing exceptions from constructors

Yes, throwing an exception from the failed constructor is the standard way of doing this. Read this FAQ about Handling a constructor that fails for more information. Having a init() method will also work, but everybody who creates the object of mutex has to remember that init() has to be called. I feel it goes against the RAII principle.

Can constructors throw exceptions in Java?

Yes, constructors can throw exceptions. Usually this means that the new object is immediately eligible for garbage collection (although it may not be collected for some time, of course). It's possible for the "half-constructed" object to stick around though, if it's made itself visible earlier in the constructor (e.g. by assigning a static field, or adding itself to a collection).

One thing to be careful of about throwing exceptions in the constructor: because the caller (usually) will have no way of using the new object, the constructor ought to be careful to avoid acquiring unmanaged resources (file handles etc) and then throwing an exception without releasing them. For example, if the constructor tries to open a FileInputStream and a FileOutputStream, and the first succeeds but the second fails, you should try to close the first stream. This becomes harder if it's a subclass constructor which throws the exception, of course... it all becomes a bit tricky. It's not a problem very often, but it's worth considering.

Is it okay to throw exceptions from the constructor in this case?

I don't see anything wrong from throw an exception in the constructor. It means that the object can't be created in a valid state.

Personally you throw the right exception, but don't use custom exceptions if you can use Java exceptions InvalidLevelException and InvalidYearException should be replaced with IllegalArgumentException while NullPointerException is the right exception if an argument is null.

Another thing i would change is the style: Check your arguments then do everything else.

public Course(String name, String code, char level, int academicYear)
{
if (name == null) {
throw new NullPointerException("Name can not be null.");
}
if (code == null) {
throw new NullPointerException("Code can not be null.");
}

if (indexOf(level, VALID_LEVEL) == -1) {
throw new InvalidLevelException("Level must be one of "
+ "characters defined in the public array in Course.");
}

if (String.valueOf(academicYear).length() != NUMBER_OF_DIGITS_IN_YEAR) {
throw new InvalidYearException("Year must be a four digit number!");
}

serialNumber = nextSerialNumber++;
this.code = code;
this.academicYear = academicYear;
this.level = level;
this.name = name;
}

(p.s if the object can't be created, why increment serial number?)

It's very elegant right? -- Another thing is to make the messages more specific.

Anyway, i think the best source is the entire JDK platform since it's a common pattern to thrown an exception in the constructor.


As Luiggi Mendoza said in comments, it's HashMap constructor if you need a prof for your teacher

187     public More ...HashMap(int initialCapacity, float loadFactor) {
188 if (initialCapacity < 0)
189 throw new IllegalArgumentException("Illegal initial capacity: " +
190 initialCapacity);
191 if (initialCapacity > MAXIMUM_CAPACITY)
192 initialCapacity = MAXIMUM_CAPACITY;
193 if (loadFactor <= 0 || Float.isNaN(loadFactor))
194 throw new IllegalArgumentException("Illegal load factor: " +
195 loadFactor);
196
197 // Find a power of 2 >= initialCapacity
198 int capacity = 1;
199 while (capacity < initialCapacity)
200 capacity <<= 1;
201
202 this.loadFactor = loadFactor;
203 threshold = (int)(capacity * loadFactor);
204 table = new Entry[capacity];
205 init();
206 }

Is it wise to throw exceptions in a constructor?

As to the concrete question, surely it's legal to throw exceptions in a constructor. There's no other sane way to prevent the "DB class" instance from being used with a broken connection.

As to the concrete functional requirement, you've another major problem. You should not be creating a DB connection in the constructor of a "DB class" and surely not make it static. This indicates that you're intending to keep the connection open as long as the instance of the "DB class" lives in Java's memory. This is in turn a very bad idea. The connection should instead be created in the very same try block as where you're executing the SQL query/queries. The connection should also be closed in the finally block of that try block. This prevents resource leaking in long term which would otherwise cause your application to crash because the DB server times out the resource because it's been open for too long, or runs out of resources because too many connections have been opened.

See also:

  • How often should Connection, Statement and ResultSet be closed in JDBC?
  • JDBC MySql connection pooling practices to avoid exhausted connection pool
  • When my app loses connection, how should I recover it?


Related Topics



Leave a reply



Submit