【问题标题】:Error C2280 mutex in a class C++C++ 类中的错误 C2280 互斥锁
【发布时间】:2015-10-06 13:32:31
【问题描述】:

我在类中声明互斥锁时遇到问题,每当我尝试实例化该类时,就会出现错误 C2280。我的项目也是模拟餐饮哲学家的问题。

声明:

class Fork
{

public:

struct _position
{
    float x;
    float y;
};

Fork();
Fork(int num_phil_, int new_index_);
_position ReturnWorkPosition(){ _position return_position_; /*position_mutex_.lock();*/ return_position_ = work_position_; 
                                    /*position_mutex_.unlock();*/ return return_position_; };
float ReturnRotation(){ return rotation_; };

void CalculateWorkPosition(int master_index_);
void ResetWorkPosition(){ /*position_mutex_.lock();*/ work_position_ = orig_position_; /*position_mutex_.unlock();*/ };
void TakeOwnership(int master_index_);
void RelinquishOwnership();

private:

int index_;
int num_philosophers_;
float rotation_;

_position orig_position_;
_position work_position_;

//std::mutex master_mutex_;
//std::mutex position_mutex_;
};

实例化:

for (int i = 0; i < num_philosophers_; i++)
{
    Fork temp_fork_(num_philosophers_, i);
    fork_.push_back(temp_fork_);
}

编辑:: 新声明:

class Fork
{

public:

Fork();
Fork(int num_phil_, int new_index_);

Fork(Fork const&) = delete;
Fork& operator=(Fork const&) = delete;

struct _position
{
    float x;
    float y;
};

_position ReturnWorkPosition(){ _position return_position_; /*position_mutex_.lock();*/ return_position_ = work_position_; 
                                    /*position_mutex_.unlock();*/ return return_position_; };
float ReturnRotation(){ return rotation_; };

void CalculateWorkPosition(int master_index_);
void ResetWorkPosition(){ /*position_mutex_.lock();*/ work_position_ = orig_position_; /*position_mutex_.unlock();*/ };
void TakeOwnership(int master_index_);
void RelinquishOwnership();

private:

int index_;
int num_philosophers_;
float rotation_;

_position orig_position_;
_position work_position_;

//std::mutex master_mutex_;
//std::mutex position_mutex_;
};

错误信息:

Error   18  error C2280: 'Fork &Fork::operator =(const Fork &)' : attempting to reference a deleted function    c:\program files (x86)\microsoft visual studio 12.0\vc\include\xutility 2045    1   Lab3e

Error   13  error C2280: 'Fork::Fork(const Fork &)' : attempting to reference a deleted function    c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0 600 1   Lab3e

新实例化:

for (int i = 0; i < num_philosophers_; i++)
{
    Fork temp_fork_(num_philosophers_, i);
    fork_.emplace_back(temp_fork_);
}

【问题讨论】:

标签: c++ class mutex


【解决方案1】:

您需要删除复制构造函数和复制赋值运算符。你不能复制std::mutex,因此你不能复制你的类的一个实例,你只能构造或移动一个。

Fork(Fork const&) = delete;
Fork& operator=(Fork const&) = delete;

错误告诉您您正在尝试引用已删除的函数,即复制构造函数,因为push_back 正在尝试复制您的temp_fork_。相反,我会使用emplace_back 就地创建Fork

for (int i = 0; i < num_philosophers_; i++)
{
    fork_.emplace_back(num_philosophers_, i);
}

或者

for (int i = 0; i < num_philosophers_; i++)
{
    Fork temp_fork_(num_philosophers_, i);
    fork_.push_back(std::move(temp_fork_));
}

旁注
您可以使用std::lock_guard 来手动锁定和解锁std::mutex,而不是手动锁定和解锁std::lock_guard,这是一个设置为通过RAII 处理锁定/解锁互斥锁的类

void ResetWorkPosition()
{
    std::lock_guard<std::mutex> lock(position_mutex_);  // position_mutex_ is now locked
    work_position_ = orig_position_;
};  // lock fell out of scope, position_mutex_ is now unlocked

_position ReturnWorkPosition()
{
    _position return_position_;
    std::lock_guard<std::mutex> lock(position_mutex_);  // position_mutex_ is now locked
    return_position_ = work_position_;
    return return_position_;
};

【讨论】:

  • 我不确定我是否关注return 什么,矢量fork_
  • 哦,对不起,我的意思是锁守卫。另外我应该在哪里放置代码来删除复制构造函数?谢谢。
  • @AlexL 你不需要return lock_guard,它是一个函数局部变量,你希望它超出范围,当它发生时它会调用unlock on为您提供互斥锁。您应该将已删除的复制构造函数放在您的类主体中,可能就在您声明构造函数之后。
  • 当这些函数已经被隐式删除时,为什么还要显式删除它们? std::vector 还需要一种类型——我相信——可复制或不可移动,所以正如 sbabbi 提到的,你必须至少定义其中一个函数。
  • @LightnessRacesinOrbit:那么这里的正确术语是什么?阅读标准不是我的强项,但 c++14 草案中的 §12.8 23 说:A **defaulted** copy/move assignment operator for class X is **defined as deleted** if X has: [...] (23.4) a potentially constructed subobject of class type M (or array thereof) that cannot be copied/moved [...] 和例如之前的第 20 点声明 If the definition of a class X does not explicitly declare a move assignment operator, one will be **implicitly declared as defaulted** if [...]。这就是我混淆的隐式删除
【解决方案2】:

正如@sbabbi 在 cmets 中对@CoryKramer 的回答所指出的那样,本质上,问题在于您的类需要有一个复制或移动构造函数,并且因为它的一些成员(互斥体)没有自己的一个,编译器隐式删除(我的术语)Fork 的那些特殊函数。因此,您必须自己为Fork 实现其中至少一个或使用指针(见下文)。

说明

为了在容器中存储,您的类T 必须满足某些要求。对于 std::vector 和直到 c++11,T 必须是 CopyAssignable 和 CopyConstructible。然而,从 c++11 开始,具体要求取决于您实际尝试调用的函数(T 始终必须是可擦除的)。

本质上,这意味着,当你想使用push_back 时,你的类型必须有一个复制构造函数,即使你正在使用emplace_back,你仍然至少需要一个移动构造函数。合理的是,如果 push/emplace_back 导致重新分配,则必须将元素从旧内存区域移动到新内存区域。

现在复制或移动mutex 没有多大意义,这就是为什么它没有任何这些成员函数(它们被标准声明为已删除)。因此,您的编译器也不会为您的 Fork 类隐式定义这些复制/移动构造函数,而是隐式删除它们,然后给出您尝试使用已删除函数的错误。

可能的解决方案

您可以定义自己的复制构造函数,如下所示:

Fork::Fork(const Fork& other) {
    /* potentially locking a mutex of other, 
       which would have to be declared mutable */
    index_            =other.index_;
    num_philosophers_ =other.num_philosophers_;
    rotation_         =other.rotation_;
    orig_position_    =other.orig_position_;
    work_position_    =other.work_position_;
}

问题在于,在(多线程)程序的上下文中定义复制构造函数的正确语义可能很困难。如果您只需要将 Forks 插入到向量中,并且在程序的进一步执行过程中没有修改,那么您应该可以忽略互斥锁。

但是,最好存储指向Fork 的指针:

for (int i = 0; i < num_philosophers_; i++) {      
    fork_.push_back(std::unique_ptr<Fork>(new Fork(num_philosophers_, i)));
    //or if your compiler is c++14 compatible:
    fork_.push_back(std::make_unique<Fork>(num_philosophers_, i));      
}

第三,您可以使用不同的容器,例如 std::list 而不是 vector(尽管您仍然必须使用 emplace_back 而不是 push_back)。

【讨论】:

  • 您好,谢谢您的回答。我已在您发布的复制构造函数中添加了解决方案,但错误仍然存​​在。有趣的是,尽管您说错误应该只在我尝试push_back 时发生,但即使我根本不尝试使用向量并且只声明它std::vector&lt;Fork&gt; fork_;,错误仍然会发生。任何帮助将不胜感激。
  • @AlexL:你用的是什么编译器?请提供MCVE
  • 呃...我使用的是 Visual Studio Professional 2013?我尝试使用Fork 类和vector 创建一个新应用程序来存储它们,但它编译得很好,这很令人费解。如果这可能是一个问题,实际项目是一个 OpenGL 项目。
  • 我已经为我的完整项目添加了一个链接,这个可以很好地编译并显示图形界面。如果您进入Fork.h 并取消注释mutexes 中的任何一个,那么您将收到错误消息。 link
  • @AlexL:对不起,我希望你明白我不会为你分析你的整个申请。我建议只复制您的项目,然后删除不相关的部分,直到错误消失。除此之外:您的编译器也抱怨缺少复制赋值运算符,因此您可能也应该实现那个。
猜你喜欢
  • 2015-09-10
  • 1970-01-01
  • 1970-01-01
  • 2015-08-27
  • 2022-07-31
  • 1970-01-01
  • 2021-07-19
  • 1970-01-01
相关资源
最近更新 更多