简体   繁体   English

我应该删除内部创建线程的类的复制构造函数和赋值运算符吗?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM