Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot catch in the initialize list

Tags:

c++

For the following code:

#include <iostream>

struct Str
{
    Str() { throw 100; }
};

class Cla
{
public:
    Cla()
    try : m_mem() { }
    catch(...)
    {
        std::cout << "Catch block is called"<< std::endl;
    }
private:
    Str m_mem;
};

int main()
{
    Cla obj;
}

I tried to catch the exception in the catch block. But after the catch block is run, the system still calls std::terminate to terminate the program. I didn't re-throw the exception in the catch block, can you tell me why the system crashes? Thanks!

Here is a test on compiler explorer: https://godbolt.org/z/74sTcxrY4

like image 621
Wei Li Avatar asked Dec 01 '22 13:12

Wei Li


2 Answers

You're contradicting yourself.

I tried to catch the exception in the catch block. But after the catch block is run

If the catch block is run, you succeeded catching the exception from the initializer list. You're just surprised by what happened next.

First, let's think about what happens when a constructor throws: the object is not constructed. Right? the constructor never finished setting it up, so you can't use it for anything.

int main() {
   Cla obj;     // member subobject constructor throw, but we caught it!
   obj.print(); // but we still can't use this here, because the constructor never completed
}

So it doesn't really make sense to let you swallow the exception here. You can't handle it, because you can't go back and re-try constructing your member and base-class subobjects. If you don't have a properly-constructed object, the only way C++ has of dealing with that is to unwind the block scope in which that object would otherwise be assumed to be ... well, a real object.

Hence, per the documentation:

Every catch-clause in the function-try-block for a constructor must terminate by throwing an exception. If the control reaches the end of such handler, the current exception is automatically rethrown as if by throw;. The return statement is not allowed in any catch clause of a constructor's function-try-block.

... and equivalently in the standard (draft)

The currently handled exception is rethrown if control reaches the end of a handler of the function-try-block of a constructor or destructor. Otherwise, flowing off the end of the compound-statement of a handler of a function-try-block is equivalent to flowing off the end of the compound-statement of that function (see [stmt.return])

like image 183
Useless Avatar answered Dec 05 '22 05:12

Useless


There is no way to swallow an exception in a constructor's function catch block. It will necessarily throw something, the caught exception if control reaches the end of the catch block. The only way around this is to std::terminate or otherwise abort before then.

From cppreference:

Every catch-clause in the function-try-block for a constructor must terminate by throwing an exception. If the control reaches the end of such handler, the current exception is automatically rethrown as if by throw;. The return statement is not allowed in any catch clause of a constructor's function-try-block.

This is intentional and beneficial. It would not make sense to return from a constructor that did not complete, it would allow an object to be accessible despite not actually having been created.

Such a catch block can be used to log errors, release resources (if you aren't using RAII) and perform other similar cleanup. But it can't prevent an exception from propagating.

like image 20
François Andrieux Avatar answered Dec 05 '22 06:12

François Andrieux