[英]Is the implementation of ThreadRAII correct in the Effective Modern C++ book?
书中的第 37 项说明了 ThreadRAII 的实现,它可以加入线程或在线程被销毁时将其分离。 通过声明析构函数,编译器不会生成移动操作,但在书中,作者说没有理由不能移动它们,并说编译器会生成正确的移动操作,并建议我们使用 '= default ' 执行。
#include <thread>
class ThreadRAII
{
public:
enum class DtorAction { join, detach };
ThreadRAII(std::thread&& t, DtorAction a)
: action(a)
, t(std:: move(t))
{}
~ThreadRAII()
{
if(t.joinable())
{
if(action == DtorAction::join)
t.join();
else
t.detach();
}
}
ThreadRAII(ThreadRAII&&) = default;
ThreadRAII& operator=(ThreadRAII&&) = default;
std::thread& get() { return t; }
private:
DtorAction action;
std::thread t;
};
int main()
{
ThreadRAII t{std::thread{[]{}}, ThreadRAII::DtorAction::join};
t = ThreadRAII{std::thread{[]{}}, ThreadRAII::DtorAction::detach};
return 0;
}
但在上面的例子中,std::terminate 被调用了。
我认为默认的移动构造函数应该没问题,但移动赋值不行,因为移动赋值必须在获取新资源之前释放当前资源。 否则,分配将破坏可连接的线程,从而导致程序终止。
我没有在本书的勘误表中看到这个问题。 这本书说默认的移动赋值运算符应该没问题真的错了吗? 我想确定并让其他人查看它以便与作者联系。
这就是我认为应该是的:
#include <thread>
class ThreadRAII
{
public:
enum class DtorAction { join, detach };
ThreadRAII(std::thread&& t, DtorAction a)
: action(a)
, t(std:: move(t))
{}
~ThreadRAII()
{
release();
}
ThreadRAII(ThreadRAII&&) = default;
ThreadRAII& operator=(ThreadRAII&& rhs)
{
release();
action = rhs.action;
t = std::move(rhs.t);
return *this;
}
std::thread& get() { return t; }
void release()
{
if(t.joinable())
{
if(action == DtorAction::join)
t.join();
else
t.detach();
}
}
private:
DtorAction action;
std::thread t;
};
int main()
{
ThreadRAII t{std::thread{[]{}}, ThreadRAII::DtorAction::join};
t = ThreadRAII{std::thread{[]{}}, ThreadRAII::DtorAction::detach};
return 0;
}
是的,这是违反 3(5) 的明确规则。
一旦你有一个自定义的 dtor,你必须让你的特殊赋值和构造函数同样自定义。 在这里,销毁的线程导致连接或分离而分配给不连接的事实相对不一致。
作者大概想过assigning-to-empty的情况,算出来也还好,没想到assigning-to-engaged。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.