What happens if the constructor throws an exception?

Will we get UB? I tried this:

#include <iostream> struct B { B(){ std::cout << "B()" << std::endl; } ~B(){ std::cout << "~B()" << std::endl; } }; struct A { B b; A(){ std::cout << "A()" << std::endl; throw std::exception(); } ~A(){ std::cout << "~A()" << std::endl; } }; int main() { A a; } 

the handle was not called for both A and B Actual conclusion:

 B() A() terminate called after throwing an instance of 'std::exception' what(): std::exception bash: line 7: 21835 Aborted (core dumped) ./a.out 

http://coliru.stacked-crooked.com/a/9658b14c73253700

So, whenever a constructor throws a block area during variable initialization, do we get UB?

+21
source share
2 answers

No, throwing an exception is the best way to report an error while creating the object. (Since there is no return value, there is no other way than creating a headless object, which is bad style in C ++.)

From the man Bjarna Straustrup himself: http://www.stroustrup.com/bs_faq2.html#ctor-exceptions

Re: "But my destructor was not named"

Actually. C ++ says that the lifetime of an object begins when the constructor completes. And it ends right when the destructor is called. If ctor throws, then dtor is not called.

(But dtors of any member variable objects whose ctor had already been executed before the ctor had completed before are called.)

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

Your question about why "~ B" was not called in your specific code is because you did not catch the exception in main. If you change your code so that main catches the exception, "~ B ()" will be called. But when an exception is thrown that does not have an interceptor, an implementation can terminate the program without calling destructors or destroying statically initialized objects.

Link in C ++ 11 standard (highlighted by me):

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

1 In some situations, exception handling should be discontinued for less sophisticated error handling methods.

...

2 In such cases, std :: terminate () is called (18.8.3). In a situation where the corresponding handler is not found, it is determined by the implementation whether the stack will be unwound before calling std :: terminate ().

As an additional note, in the general case with gcc and clang, ~B will be called anyway in your sample program, while it will not be called with MSVC ~B Exception handling is complex, and the standard allows compiler authors to experiment with them and choose which implementation they consider best in this regard, but they cannot choose undefined behavior.

If it is really important for your program that destructors are called even in this case, then you should make sure that you catch exceptions in main , so that your code is portable (working on all relevant compilers).

+37
source

Throwing exceptions in the constructor is a standard way of handling errors and is not undefined. If you create a constructor, it is assumed that the object was not initialized correctly, so its destructor is not called.

+5
source

All Articles