Date: Thu, 12 Jan 2023 11:27:05 -0300
I'm curious, do you often hit this issue where global objects throw
exceptions? Or it's a "just in case" thing?
I'm asking because I have never hit that, ever. But then again, I never
create global objects that are complex enough that they could throw
exceptions. Or if I do, I just make them lazily instantiated:
Obj& getObj() { static Obj obj; return obj; }
(but I avoid that as much as possible).
Breno G.
On Thu, Jan 12, 2023 at 7:24 AM 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.
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
exceptions? Or it's a "just in case" thing?
I'm asking because I have never hit that, ever. But then again, I never
create global objects that are complex enough that they could throw
exceptions. Or if I do, I just make them lazily instantiated:
Obj& getObj() { static Obj obj; return obj; }
(but I avoid that as much as possible).
Breno G.
On Thu, Jan 12, 2023 at 7:24 AM 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.
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2023-01-12 14:27:18