[英]Should I delete a copy constructor and an assignment operator of a class that internally creates threads?
When a class owns thread and mutex objects, are there any potential dangerous situations where a copy/assignment would be dangerous, meaning that copy constructor and assignment should be deleted? 当一个类拥有线程和互斥对象时,是否存在任何潜在的危险情况,其中复制/赋值将是危险的,这意味着应该删除复制构造函数和赋值?
Consider this sample code: 考虑以下示例代码:
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
};
If I understand things correctly, the thread created in Method()
will not be visible outside of A
, meaning that copying with a default cctor shouldn't be problematic, because the entire state would get copied. 如果我理解正确,在Method()
创建的线程将不会在A
外部可见,这意味着使用默认cctor进行复制不应该有问题,因为整个状态将被复制。 Is my reasoning correct? 我的推理是否正确?
Any class whose (extended) state includes pointers into itself must have a deleted copy/move or must marshall that state. 任何其(扩展)状态包含指针的类必须具有已删除的副本/移动或必须编组该状态。
t = std::thread([this]
the above line stores a pointer to this
in the class's extended state. 上述行存储一个指向this
在类的延伸状态。
Default copy and move is thus inappropriate. 因此,默认复制和移动是不合适的。 Deleted is one option; 删除是一个选项; carefully and possibly expensively marshalling another. 仔细地,可能昂贵地编组另一个。
In addition, both thread and mutex are move only types. 此外,线程和互斥体都只是移动类型。 So copy will be implicitly deleted. 因此将隐式删除副本。
Your move assign/construct, however, will be written by the compiler and wrong . 但是,您的移动分配/构造将由编译器编写并且错误 。 So delete them or fix them. 所以删除它们或修复它们。
There is a idiom from languages without class-value types (like Java/C#) of having a class with state and a thread that works on the state. 没有类值类型(如Java / C#)的语言有一个成语,它有一个带状态的类和一个处理状态的线程。 This is a bad plan in a value centric language like C++. 这是一个像C ++这样以价值为中心的语言的糟糕计划。 Store your state externally (say, a shared or unique ptr), share it with your thread (as shared ptr or as observing ptr), and suddenly default move makes sense. 将您的状态存储在外部(比如,共享或唯一的ptr),与您的线程共享(作为共享ptr或观察ptr),突然默认移动是有意义的。
Without doing that, your object becomes sessile -- unable to safely move -- which cripples a lot of great C++ idioms, or forces external smart pointer wrapping. 如果不这样做,你的对象变得无序 - 无法安全移动 - 这会削弱许多优秀的C ++习语,或者迫使外部智能指针包装。
Both copy constructor and assign need to be deleted or defined. 需要删除或定义复制构造函数和赋值。 If you want to delete them, don't do anything: C++ will delete them for you implicitly. 如果要删除它们,请不要执行任何操作:C ++将隐式删除它们。
Your class has std::mutex
as a member. 你的类有std::mutex
作为成员。 Its copy constructor and assignment operators are deleted. 其副本构造函数和赋值运算符将被删除。 This makes C++ delete copy constructor and assignment operator of your class as well, because generating default behavior for them would require invoking deleted members. 这使得C ++也可以删除类的复制构造函数和赋值运算符,因为为它们生成默认行为需要调用已删除的成员。
Note: Deletion is not your only option: if you find it useful to make copies of A
or make them assignable, you have an option to define a copy constructor and an assignment operator that create a new thread and a new mutex, and copy relevant parts of your object to support the semantics that you find useful. 注意:删除不是您唯一的选择:如果您发现制作A
副本或使其可分配很有用,您可以选择定义复制构造函数和赋值运算符,以创建新线程和新互斥锁,并复制相关对象的一部分,以支持您认为有用的语义。 Even though C++ wouldn't do it for you by default, you have an option to do it manually. 即使C ++默认情况下不会为您执行此操作,您也可以选择手动执行此操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.