Considering following code, I or, rather the developer of original code, would expect that function-local object would be destroyed before the call to [[noreturn]] fubar() function.
#include <iostream>
#include <iostream>
using std::cout;
using std::endl;
class Static
{
public:
Static() { cout << "Static::Static" << endl; }
~Static() { cout << "Static::~" << endl; }
};
class Automatic
{
public:
Automatic() { cout << "Automatic::Automatic" << endl; }
~Automatic() { cout << "Automatic::~" << endl; }
};
[[noreturn]] void fubar() {
cout << "It's FUBAR" << endl;
throw 42;
}
void foo() {
Automatic a;
static Static b;
fubar();
cout << "It's fine." << endl;
}
int main()
{
try {
foo();
}
catch(int a)
{
cout << "main() was FUBARed. Answer is " << a << endl;
}
return 0;
}
Apparently that's not true. E.g. output after compiling with GCC 10 shows that Automatic was destroyed after fubar was entered, but it happens before exception was caught. It's exactly same behaviour as if fubar() wasn't noreturn.
Automatic::Automatic
Static::Static
It's FUBAR
Automatic::~
main() was FUBARed. Answer is 42
Static::~
Is that a defined behaviour? It is a result of stack unwinding for exception handling. Further investigation shows that exit(0); (which is declared as [[noreturn]] itself).
[[noreturn]] void fubar() {
cout << "It's FUBAR" << endl;
exit(0);
}
result to incomplete destruction of automatics:
Automatic::Automatic
Static::Static
It's FUBAR
Static::~
Does this actually mean that calls to standard functions declared as [[noreturn]] is a big "no" for an OS that doesn't do clean-up after process execution and that the use of local variables to initialize any OS-wide resources is not safe if any such call is possible (no proper deinitialization will happen) or I'm finding a flaw?
As expected;
[[noreturn]]is a red herring here, as thefubar()does not return (and thus fulfills the requirement that the attribute is intended to signal).From [dcl.attr.noreturn]/2 and [dcl.attr.noreturn]/3 [emphasis mine]:
the
[[noreturn]]attribute is only essential for functions that do return in some execution path (which is an error that a compiler may help flagging); namely that a function annotated as[[noreturn]]that actually does return results in undefined behaviour, and compilers are recommended to mark programs which contain returning program paths for[[noreturn]]annotated functions with a warning.