Catching Exceptions from a Constructor's Initializer List

Catching exceptions from a constructor's initializer list

Have a read of http://weseetips.wordpress.com/tag/exception-from-constructor-initializer-list/)

Edit: After more digging, these are called "Function try blocks".

I confess I didn't know this either until I went looking. You learn something every day! I don't know if this is an indictment of how little I get to use C++ these days, my lack of C++ knowledge, or the often Byzantine features that litter the language. Ah well - I still like it :)

To ensure people don't have to jump to another site, the syntax of a function try block for constructors turns out to be:

C::C()
try : init1(), ..., initn()
{
// Constructor
}
catch(...)
{
// Handle exception
}

How to catch the exception in initialization list?

I think the syntax is like this (even though it's better to catch such things in the caller. And what are you going to do once you caught it?)

Bar::Bar()
try
: Foo(1)
{
}
catch( const SomeException &e )
{
}

exception handling in constructor’s initializer list

Firstly, if you dereference the NULL pointer standard C++ does not guarantee that that an exception will be thrown, so your code is useless for this case.

Secondly, if an exception were thrown, what would your exception handler do?

Thirdly, constructor/function exception blocks are widely considered to be awaste of time - take a look at this http://www.gotw.ca/gotw/066.htm and other articles on Herb Sutter's GotW site.

C++ constructor initializer list throw exceptions

You cannot actually catch an exception in a constructor. You can handle it, but you have to rethrow it or another exception. The reason is about object integrity and object lifetimes:

If the construction of a throws, a part of c has not been initialized and is completely missing - lifetime of a never starts. a is not an optional part of C, otherwise it had to be a pointer or a std::optional (since C++14 - boost::optional before that).

So how do you assemble a C if one of its vital parts cannot be constructed? You can't. c can never start to exist as a complete object, so there is no way you can exit the constructor normally. That's the reason why if construction of a member object fails, construction of the whole object has to fail, i.e. has to throw an exception.

If you don't throw an exception in C::C's catch block, the compiler will do so for you.

C++ Standard, §15.3,15:

The currently handled exception is rethrown if control reaches the end of a handler of the function-try-block of a constructor or destructor.

For a broader treatment on that topic, see http://www.gotw.ca/gotw/066.htm

Exception in constructor initialization list

I want to understand what will happen if c(new char[1024]) will throw exception? Will b correctly destroyed?

Yes. When a constructor throws, any already-constructed members and base classes are destructed automatically.

Can caller catch this exception?

Yes.

If yes, what will be the value of a?

nullptr, because that is what you initialized a with, and the exception is thrown before you can assign a new value to a.

Will ~A() be called?

No. If A() does not complete cleanly, the ~A() destructor is not called. And you are not calling delete on any fully constructed A object, either.

Is it good practice to call functions in the constructor initialization list that can throw an exception?

That is perfectly fine. Just make sure that any previously constructed members are cleaned up properly to avoid any leaks.

For example:

class A
{
B * b;
char * c;

B* getB() { return new B; }
char* getC() { return new char[1024]; }

public:
A() : b(getB()), c(getC())
{}

~A()
{
delete b;
delete[] c;
}
};

b is initialized before c, so if getC() throws then the memory that b is pointing at will be leaked.

You can fix that in one of two ways:

  1. moving the allocations into the constructor body and using normal exception handling:
class A
{
B * b;
char * c;

B* getB() { return new B; }
char* getC() { return new char[1024]; }

public:
A()
{
b = getB();
try
{
c = getC();
}
catch(...)
{
delete b;
throw;
}
}

~A()
{
delete b;
delete[] c;
}
};

  1. using smart pointers:
class A
{
std::unique_ptr<B> b;
std::unique_ptr<char[]> c;

std::unique_ptr<B> getB() { return std::make_unique<B>(); }
std::unique_ptr<char[]> getC() { return std::make_unique<char[]>(1024); }

public:
A() : b(getB()), c(getC())
{}

~A() = default;
};

How to use exception handling with initializer-list with constructor?

On first view, it's not clear whether you intend CVector to responsibility for owning the dynamic of integers or not. You probably do.

Almost without fail, you will want each class in your program to manage at most one dynamic resource (such as allocated memory). This is because the job becomes onerous when there is more than one resource.

In your case, the resource is the int array. So let's give CVector the responsibility, and let's manage that responsibility using a unique_ptr:

#include <memory>
#include <cstddef>
#include <algorithm>

struct CVector
{
CVector(std::size_t initial_size)
: data_ { std::make_unique<int[]>(initial_size) }
, size_ { initial_size }
{
}

// we will probably want the vector to be copyable
CVector(CVector const& other)
: data_ { std::make_unique<int[]>(other.size_) }
, size_ { other.size_ }
{
auto first = other.data_.get();
auto last = first + other.size_;
std::copy(first, last, data_.get());
}

// move consruction is defaultable because it is enabled for
// unique_ptr

CVector(CVector&&) = default;

// assignment

CVector& operator=(CVector const& other)
{
auto temp = other;
swap(temp);
return *this;
}

CVector& operator=(CVector&& other) = default;

// no need for a destructor. unique_ptr takes care of it

void swap(CVector& other) noexcept
{
using std::swap;
swap(data_, other.data_);
swap(size_, other.size_);
}

private:
// defer memory ownership to a class built for the job.
std::unique_ptr<int[]> data_;
std::size_t size_;
};

Why can an exception occur when initializing the constructor list parameter?

Here's an example:

struct S
{
S(char *);
};

int main()
{
S s(new char[0x7FFFFFFF]);
}

The new char[0x7FFFFFFF] might throw an out-of-memory exception.

How to use correctly Constructor-Function-Try-Block?

I didn't understand the second and third paragraphs; it looks to me like it is contradictory, because it is said that to handle exceptions from a constructor-init list we use ctor-function-try block, and from the other side it said that "it's worth noting that an exception... such exceptions are not a part from function-try-block...".

Those "..."s are important. The actual quote was:

an exception can happen while initializing the constructor's parameters

Emphasis added. That is, the paragraph is about the initialization of parameters before calling the constructor.



And now the exception in not handled and std::terminate is called?!

Precisely. This behavior has nothing to do with the text you quoted. This happens because function-level try blocks on constructors cannot swallow exceptions.

If a member of an object fails to be constructed, the object itself has failed to be constructed. Members of an object are not optional (well, except for std::optional ones ;) ); they must be properly constructed. Employee's constructor failed to initialize Employee::age_. The function catch block was called.

But the Employee object still failed to be constructed. There is only one way in C++ to communicate that an object has failed to be constructed: throwing an exception. And C++ just so happens to have an exception right there in the constructor's function try block.

As such, when a constructor's function-level catch block exits, the exception is always rethrown, exactly as if you had issued a throw e; at the end of the block.

The only thing a constructor's function-level try/catch block can do is cleanup. They cannot stop the propagation of an exception. Reasonable use of RAII makes constructor function try/catch blocks unnecessary in nearly all cases.

How to catch exception which happens at initialization of Java class field?

is it possible to do it while initializing the field?

You can define a method:

class a {
int a = aValue();

private int aValue() {
try
{
return 1/0;
}
catch (Throwable a){
// ...but now you need to return something, or (re)throw an exception.
}
}
}

or use an instance initializer:

class a {
int a;

{
try
{
this.a=1/0;
}
catch (Throwable a){
// You don't need to do anything here, unless `a` were `final`.
}
}
}

but note that instance initializers are inlined into the constructor (or, at least, any constructor that invokes super(...) explicitly or implicitly, rather than this(...)), so this is effectively the same as putting it in the constructor as in the question.

catch the exception from class member initialization in-place

You actually can not catch an exception without a rethrow (which is implicit), if an exception occurs in the initializer list:

include <stdexcept>

struct E { E(int) { throw std::runtime_error("E"); } };
class A {
E e {1};
public:
A()
try
{}
catch(...) {
std::cout << "Exception" << std::endl;
}
};
int main()
{
A a;
return 0;
}

Gives:

Exception
terminate called after throwing an instance of 'std::runtime_error'
what(): E
Aborted

However, you can catch it, even without mentioning the member in the initializer list.

Hence, you may have an exception safe initialization of the member and handle exception critical assignment/initialization inside the constructors body (as other (deleted) answers suggested).



Related Topics



Leave a reply



Submit