C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Catch exception thrown from constructor of global object

From: Lénárd Szolnoki <cpp_at_[hidden]>
Date: Thu, 12 Jan 2023 10:54:51 +0000
On 12 January 2023 10:23:45 GMT, Frederick Virchanza Gotham via Std-Proposals <std-proposals_at_[hidden]> wrote:
>Let's say we have three global objects like in the following program:
>
> SomeClass0 g_objA;
> SomeClass1 g_objB;
> SomeClass2 g_objC;
>
> int main(void)
> {
>
> }
>
>Well the program's screwed if either of those 3 constructors throw an exception.
>
>When I'm starting to write a new program nowadays, I always do:
>
> #include <exception> // set_terminate
> #include <optional> // optional
> using std::optional;
> optional<SomeClass0> g_objA;
> optional<SomeClass1> g_objB;
> optional<SomeClass2> g_objC;
>
> int main(void)
> {
> std::set_terminate( my_terminate_handler);
>
> try
> {
> g_objA->emplace();
> g_objB->emplace();
> g_objC->emplace();
> }
> catch(...) { /* deal with problems in here */ }
> }
>
>The benefits to this strategy are as follows:
>(1) My terminate handler is set before the global objects are constructed
>(2) I can catch the exceptions thrown when the global objects are constructed
>
>Now if you were to ask me . . . . I would almost go so far as to
>propose that C++26 should deprecate defining a global object that
>doesn't satisfy 'is_trivial' so that all such objects would be wrapped
>in an std::optional<T> and emplaced within the body of 'main', but of
>course I know that I won't get any support on that. So I can just
>maintain my own personal programming policy and be content with that.
>
>But is there any other little change we can make that would make the
>situation a little better for the 98% of programmers who don't adopt
>my own personal policy? At the very least, maybe we should provide a
>way of ensuring that the terminate handler is set before the
>construction of a global object takes place? Perhaps something like:
>
> void *my_handler(void)
> {
> // Save debugging info
> }
>
> int main(void) : set_terminate(my_handler)
> {
>
> }
>
>I've seen people try to pull this off already in C++ 20 programs by
>doing the likes of:
>
> auto const installed{ std::set_terminate(&handler) };
>
> int main(void)
> {
> // Do stuff
> }
>
>But there are two problems with this:
>Maybe some other global object will be constructed before 'installed',
>and maybe the constructor of that other global object will throw
>(2) I haven't checked the fine print in the Standard on whether or not
>the terminate handler is guaranteed to be called if a global object
>fails to construct -- I read the following on cppreference.com:
>"std::terminate is called if the constructor or the destructor of a
>static or thread-local (since C++11) object throws an exception"
>but I'm not sure if the 'static' here includes global variables.
>
>I do think though that there should be more solid sensibility in the
>Standard surrounding the failure to construct global objects.

If not allowing "non-trivial" global objects in your codebase would be a pattern you would like to enforce, then maybe you can enforce constinit/constexpr on them. I think your optionals qualify for constinit.

Cheers,
Lénárd

Received on 2023-01-12 10:54:58