16

C++11

I am trying to make a vector of std::threads. The combination of the following three points says I can.

1.) According to http://en.cppreference.com/w/cpp/thread/thread/thread, thread’s default constructor creates a

thread object which does not represent a thread.

2.) According to http://en.cppreference.com/w/cpp/thread/thread/operator%3D, thread’s operator=

Assigns the state of [the parameter, which is a thread rvalue reference] to [the calling thread] using move semantics.

3.) According to http://en.cppreference.com/w/cpp/container/vector/vector, passing only a size type variable to a vector constructor will construct

the container with [the specified number of] value-initialized (default constructed, for classes) instances of T. No copies are made.

So, I did this:

#include <iostream>
#include <thread>
#include <vector>

void foo()
{
    std::cout << "Hello\n";
    return;
}

int main()
{
    std::vector<std::thread> vecThread(1);
    vecThread.at(0) = std::thread(foo);
    vecThread.at(0).join();
    return 0;
}

This runs as expected in VC11 and g++ 4.8.0 (online compiler here) as seen in the following:

Console Output:

Hello

Then I tried it in clang 3.2, by toggling the compiler menu on the same webpage, which gives:

stderr: 
pure virtual method called
terminate called without an active exception

When a thread object—that represents a thread—goes out of scope before being join()ed or detach()ed, the program will be forced to terminate. I have join()ed vecThread.at(0), so the only thing left in question is the temporary thread

std::thread(foo);

in the

vecThread.at(0) = std::thread(foo);

assignment.

However, according to the web reference, threads can only be assigned by moving a thread rvalue reference. I cannot think of any way to join() or detach() a temporary thread object.

So if clang’s output is correct, then what is the use of thread’s operator=? Or is this a clang compiler bug?

In g++ 4.8.0, changing the line

vecThread.at(0) = std::thread(foo)

to

vecThread.at(0) = std::thread{foo}

(replacing parentheses with braces) still gives the expected Hello output.

However, changing the line to vecThread.at(0) = {foo} makes it complain:

g++ 4.8.0's complaint on braces:

error: converting to 'std::thread' from initializer list would use explicit constructor 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(); _Args = {}]' vecThread.at(0) = {foo};

which is too advanced—I don’t know what it means.

Making the same change in clang gives the even more advanced:

clang 3.2's complaint on braces:

error: no viable overloaded '='
vecThread.at(0) = {foo};
...
note: candidate function not viable: cannot convert initializer list
argument to 'const std::thread'
thread& operator=(const thread&) = delete;
...
note: candidate function not viable: cannot convert initializer list
argument to 'std::thread'
thread& operator=(thread&& __t) noexcept

and I don’t know what that means either.

I cannot use VC11 to corroborate the above

vecThread.at(0) = {foo}

problems because VC11, as of the November 2012 CTP compiler, does not support uniform initialization syntax on the Standard Library.

CodeBricks
  • 1,771
  • 3
  • 17
  • 37
  • Did you compile with `-pthread`? The code looks fine, albeit a bit verbose. – Kerrek SB Mar 16 '13 at 04:24
  • Do you mean I should add `–pthread` to the `compiler/interpreter` arguments text field of the online compiler? I added it to the webpage's text field's original compiler/interpreter arguments, making it `-std=c++11 -Wall -W -pedantic -O2 –pthread` on clang, but got the same results with the `terminate` being called. – CodeBricks Mar 16 '13 at 04:43
  • Well, [this code](http://ideone.com/4B2Elt) works for me when compiled with `-std=c++0x -pthread`... – Kerrek SB Mar 16 '13 at 04:46
  • I wrote a little snippet for liveworkspace named `cfor-dtor tracer`. Play with it instead of std::thread – borisbn Mar 16 '13 at 04:59
  • 1
    AFAIK, this exception throws when you compile with flag `-stdlib=libstdc++`. And this is old known [bug](http://llvm.org/bugs/show_bug.cgi?id=12730). Some suggest using a llvm c++ library, but I can't confirm it now. You can check it, if you have installed this library(add `-stdlib=libc++` to compiler arguments). – awesoon Mar 16 '13 at 05:11
  • @soon: make that an answer. – rici Mar 16 '13 at 06:06

1 Answers1

8

Your first example is correct. Throwing an exception is a known bug, when you using clang with libstdc++. To solve it, you have to install libc++(llvm version of c++ library). See an example of compiling with libc++ below

#include <thread>

int main()
{
    std::thread t([] () {});
    t.join();
    return 0;
}

$ clang++ -std=c++11 -stdlib=libc++ main.cpp -o main -lc++ -lsupc++ -lpthread

P.S. See here, why is the flag -lsupc++ required too.

Community
  • 1
  • 1
awesoon
  • 32,469
  • 11
  • 74
  • 99