Details in the process of creating an std :: thread object

I'm interested in (and confused) the details of constructing a std::thread object. According to cppreference , both the stream function and all arguments are copied to some stream storage, and then called.

1) What is the storage available for threads? Is it semantically equivalent to some streaming local storage, and are the variables destroyed when the stream function returns?

2) What is the category of argument values ​​when passing a stream function? The cppreference description shows that they are passed as l-values ​​(they are given names anyway). My tests for GCC and clang seem to be the opposite, i.e. R-values. In particular, the following code does not compile:

 void f(int& a) { std::cout << ++a << '\n'; } int main() { std::thread t(&f, 1); t.join(); return 0; } 

It compiles if we change f to

 void f(int&& a) { std::cout << ++a << '\n'; } int main() { std::thread t(&f, 1); t.join(); return 0; } 

So what does the standard say about this?

+3
c ++ multithreading language-lawyer c ++ 11 stdthread
source share
1 answer

1) This bit of text, available for streams, is not represented directly in the standard. The standard simply says that the function is called with arguments received using decay_copy .

2) If you examine decay_copy , you will find that it returns a value (because its return type is std::decay for something). Thus, the function f is called with rvalue arguments (in fact, prvalue arguments).

If you want to pass lvalues ​​(links), you can use std::ref and std::cref to carry them.

Exact quote, C ++ 11 30.3.1.2/4:

Effects: Creates an object of type thread . The new thread of execution executes INVOKE(DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...) with calls to decay_copy evaluated in the construction thread. Any return value from this call is ignored. [Note: this means that any exceptions that are not thrown out of circulation copy f will be thrown in the construction thread, and not in the new thread. -end note] If a call to INVOKE(DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...) ends with an uncaught exception, std::terminate is called.

decay_copy defined in 30.2.6 / 1:

In several places in this section, the DECAY_COPY(x) operation is used. All such uses mean a call to the DECAY_COPY(x) function and use the result where decay_copy is defined as follows:

 template <class T> typename decay<T>::type decay_copy(T&& v) { return std::forward<T>(v); } 

INVOKE defined in 20.8.2 in much the same way that cppreference describes a call in the link you provide.

+2
source share

All Articles