Re: Does the following snippet show undefined behavior?
On Sun, 30 Mar 2014 11:37:45 -0700 (PDT)
Wake up Brazil <johnkalane@yahoo.com> wrote:
I've been told that this code shows undefined behavior because of
=A73.6.3/4 in the C++11 Standard, but I don't understand this assertion.
#include <iostream>
#include <thread>
class A
{
public:
void operator()() const { std::cout << 'A' << '\n'; }
};
int main()
{
std::thread t(A{});
t.detach();
}
The problem here is that cout may be used in the thread t after the
end of main().
My interpretation of =A73.6.3/4 (applied to cout) is as follows: if
there is a use of cout in a signal handler that does not happen
before completion of destruction of objects with static storage
duration ..., the program has undefined behavior.
But the code above doesn't use cout in a signal handler. Thus, AFAIK
this paragraph doesn't apply in this case.
You have changed the wording of the standard. What it actually says is
"If there is a use of a standard library object or function not
permitted within signal handlers (18.10) that does not happen before
(1.10) completion of destruction of objects with static storage
duration and execution of std::atexit registered functions (18.5), the
program has undefined behavior."
You cannot use std::cout in a signal handler, so you cannot use it
after destruction of static objects. You therefore have undefined
behaviour because of =A73.6.3/1: "Destructors (12.4) for initialized
objects (that is, objects whose lifetime (3.8) has begun) with static
storage duration are called as a result of returning from main and as a
result of calling std::exit (18.5)." This is because any library
function which is not permitted to be called in a signal handler may
access a static object.
However you have undefined behaviour quite apart from =A73.6.3/4,
because std::cout is itself a static object. You cannot access it
after main() has returned.
If you are using a POSIX OS in the case you mention, then you should
finish main() with a call to pthread_exit() so there is no implicit
call to return. A consequence of that is that static objects will not
be destroyed until the last thread has terminated. However, that falls
outside the C++ standard itself - it is mandated by POSIX (sort of,
because POSIX does not recognize C++, but it is a necessary consequence
of what POSIX does say): the specification for pthread_exit() says
"Thread termination does not release any application visible process
resources, including, but not limited to, mutexes and file descriptors,
nor does it perform any process-level cleanup actions, including, but
not limited to, calling any atexit() routines that may exist." ... "The
process shall exit with an exit status of 0 after the last thread has
been terminated. The behavior shall be as if the implementation called
exit() with a zero argument at thread termination time."
Chris