Is what constitutes a failed initialization of block-scope static or thread storage duration variables underspecified?

后端 未结 2 589
盖世英雄少女心
盖世英雄少女心 2021-02-15 23:56

After answering this question and not finding a satisfying answer in the standard paper, I started wondering. The standard states the following w.r.t. initialization of mentione

相关标签:
2条回答
  • 2021-02-16 00:09

    The C++ specification can only define things that are contained within the C++ specification. Remember: the C++ specification defines the behavior of a virtual machine it defines. And if it doesn't define that something can happen, it certainly doesn't define the behavior of C++ around that something that it doesn't say can happen.

    According to the C++ specification, a thread can exit in exactly three ways: by returning from its main function, throwing an exception through its main function, and direct process exiting (as with std::terminate or similar functions). In short, a C++ thread cannot exit in any other way. There is no ExitThread function in standard C++. Similarly, std::thread cannot kill a thread, either externally or internally.

    Therefore, anything that does cause this thing that C++ says can't happen is, by definition undefined. I guess it wouldn't even be "undefined behavior"; it would be in that nebulous space that threading was in before C++11 actually laid down how thread interactions worked.

    The same goes for "signals", whatever those are. The C++ spec doesn't say that those can cause a function to exit. Here be dragons.

    As for longjmp, that's covered by the behavior of longjmp. When you use longjmp to exit a function, that function never finished, just as if you used throw and catch. And in C++, an object is only constructed when its constructor has completed. Therefore the object's initialization was never completed, and it is uninitialized.

    I don't have the ISO C specification (which C++ references for the behavior of longjmp), but C++11 does strongly suggest that you can equate throw/catch with longjmp/setjmp, as far as when you get undefined behavior:

    §18.10 [support.runtime] p4:
    

    The function signature longjmp(jmp_buf jbuf, int val) has more restricted behavior in this International Standard. A setjmp/longjmp call pair has undefined behavior if replacing the setjmp and longjmp by catch and throw would invoke any non-trivial destructors for any automatic objects.

    So I don't think this is underspecified. It may not be nicely and neatly laid out, but all of the pieces are there.

    0 讨论(0)
  • 2021-02-16 00:32

    Just because the text mentions one particular case doesn't imply by omission that others would be any different. If there are other ways to prevent the initialization from completing, the implementation must retry at the next execution.

    I think Nicol's answer is mostly correct, but a non-trivial constructor does not imply a non-trivial destructor. longjmp may therefore interrupt initialization such that it must be retried. This is tricky only in a multithreaded environment, where a mutex is needed to prevent a race condition between threads vying to be the first to execute the initialization. The phantom mutex object needs a non-trivial destructor even if the initialized object does not have one. The likely result is deadlock. This is probably good material for a DR.

    0 讨论(0)
提交回复
热议问题