当一个类拥有线程和互斥对象时,是否存在任何潜在的危险情况,其中复制/赋值是危险的,这意味着应该删除复制构造函数和赋值?
考虑这个示例代码:
class A : B
{
std::thread t;
std::mutex m;
public:
A() : B() {}
virtual ~A()
{
if (t.joinable())
t.join();
}
// Should I delete cctor and assignment operator?
virtual void Method()
{
t = std::thread([this]
{
std::lock_guard<std::mutex> lck(m);
... // processing
});
}
// Other methods that lock on mutex m
};
如果我理解正确的话,在 Method()
中创建的线程在 A
之外将不可见,这意味着使用默认 cctor 进行复制应该不会有问题,因为整个状态都会被复制。我的推理正确吗?
最佳答案
任何(扩展)状态包含指向自身的指针的类都必须具有已删除的拷贝/移动,或者必须编码该状态。
t = std::thread([this]
上面的行在类的扩展状态下存储了一个指向 this
的指针。
因此,默认复制和移动是不合适的。删除是一种选择;小心翼翼地、可能代价高昂地编码另一个。
此外,线程和互斥体都是仅移动类型。因此拷贝将被隐式删除。
但是,您的移动分配/构造将由编译器编写并且错误。因此删除它们或修复它们。
<小时/>没有类值类型的语言(如 Java/C#)有一个习惯用法,即拥有一个具有状态的类和一个处理该状态的线程。对于像 C++ 这样以值(value)为中心的语言来说,这是一个糟糕的计划。将您的状态存储在外部(例如,共享或唯一的 ptr),与您的线程共享(作为共享 ptr 或观察 ptr),突然间默认移动就有意义了。
如果不这样做,你的对象就会变得无柄——无法安全地移动——这会削弱许多伟大的 C++ 习惯用法,或者强制外部智能指针包装。
关于c++ - 我应该删除内部创建线程的类的复制构造函数和赋值运算符吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48137834/