I am trying to get a RAII wrapper class around std::thread to work in C++.
#include <iostream>
#include <thread>
#include <vector>
using std::cout;
using std::endl;
void threadFunction()
{
for (int i = 0; i < 20; ++i) {
cout << "thread function pointer executing..." << i << endl;
}
}
// RAII wrapper that supports automatic join
class ThreadJoinRAII
{
std::thread thread_;
public:
ThreadJoinRAII(std::thread&& t):thread_(std::move(t))
// ThreadJoinRAII()
{
cout << "ThreadJoinRAII ctor" << endl;
}
//ThreadJoinRAII(const ThreadJoinRAII& other) = delete;
//ThreadJoinRAII& operator=(const ThreadJoinRAII& other) = delete;
//ThreadJoinRAII(ThreadJoinRAII&& other):thread_(std::move(other.thread_))
//{
// cout << "ThreadJoinRAII move ctor" << endl;
//}
//ThreadJoinRAII& operator=(ThreadJoinRAII&& other)
//{
// cout << "ThreadJoinRAII move op" << endl;
// thread_ = std::move(other.thread_);
// return *this;
//}
~ThreadJoinRAII()
{
cout << "in ThreadJoinRAII dtor" << endl;
if (thread_.joinable()) {
thread_.join();
cout << "join thread id = " << thread_.get_id() << endl;
} else {
cout << "thread not joinable. id=" << thread_.get_id() << endl;
}
}
};
class Something
{
std::vector<int> vec_;
public:
Something(std::vector<int>&& v):vec_(std::move(v)) {
cout << "Something ctor" << endl;
}
};
void testRAII()
{
ThreadJoinRAII t1(std::move(std::thread(threadFunction))); // prints ThreadJoinRAII ctor
ThreadJoinRAII t2(std::thread(threadFunction)); // prints nothing
Something s1(std::vector<int>(3, 4)); // prints Something ctor
}
int main(int argc, char* argv[])
{
testRAII();
return 0;
}
The issue is that t2
line in testRAII()
prints nothing. That part I don't understand. I tried to add/remove copy operations and move operations and they didn't make any difference.
My questions are:
std::thread(threadFunction)
is already a rvalue in testRAII()
? Why do I have to move it for the constructor to work?t2
if the constructor provided was not used? I don't see ThreadJoinRAII ctor printed.s1
line prints out "Something ctor". What is the difference between t2
and s1
? Is std::thread
rvalue treated differently?BTW, I compiled the code on Ubuntu 20.04 LTS with g++ 9.3 with g++ -std=c++17 -o mt mt.m.cpp -lpthread
. mt.m.cpp
is my file name.
It may not look like it at first glance, but t2
is a function prototype, not a variable declaration (search for "most vexing parse").
You can change it to a variable by adding some parentheses:
ThreadJoinRAII t2((std::thread(threadFunction)));
then it will call your ThreadJoinRAII
constructor.