"Attempting to reference a deleted function" 将 QMutex 添加到 class 之后
"Attempting to reference a deleted function" after adding QMutex to class
我正在使用 Qt5 构建应用程序。我的程序构建并运行良好,但访问数据结构的两个线程之间存在冲突。我有一个 CanMessage 对象的 QList,我想使用 QMutex 保护其中的一些数据。但是,一旦我将 QMutex 添加到我的 class 定义中,我就会收到错误消息:
QList.h: `error: C2280:
'CanMessage::CanMessage(const CanMessage &)': attempting to reference a deleted function`.
这是我的 canmessage.h
文件:
#ifndef CANMESSAGE_H
#define CANMESSAGE_H
#include <QObject>
#include <QMutex>
#include "cansignal.h"
class CanMessage
{
public:
CanMessage();
/* snip - public function prototypes */
private:
/* snip - private prototypes and data */
QMutex m_messageMutex;
};
#endif // CANMESSAGE_H
和cansignal.h
:
#ifndef CANSIGNAL_H
#define CANSIGNAL_H
#include <QObject>
#include <QDebug>
#include <QByteArray>
class CanSignal
{
public:
CanSignal();
CanSignal(QString &signalName, quint8 &signalLength, quint8 &signalStartBit,
float &offset, float &factor, bool &isBigEndian, bool &isFloat, bool &isSigned)
{
this->m_name = signalName;
this->m_length = signalLength;
this->m_startBit = signalStartBit;
this->m_offset = offset;
this->m_factor = factor;
this->m_isBigEndian = isBigEndian;
this->m_isFloat = isFloat;
this->m_isSigned = isSigned;
}
bool setName(QString &signalName);
bool setBitLength(quint8 &length);
bool setStartBit(quint8 &startBit);
bool setOffset(float &offset);
bool setFactor(float &factor);
bool setEndianess(bool &isBigEndian);
bool setIsFloat(bool &isFloat);
bool setIsSigned(bool &isSigned);
void setValid();
void setInvalid();
void setEngineeringData(float data);
QString getName();
quint8 getBitLength();
quint8 getStartBit();
float getOffset();
float getFactor();
float getData();
bool isBigEndian();
bool isFloat();
bool isSigned();
bool getSignalValidity();
private:
QString m_name;
quint8 m_length;
quint8 m_startBit;
float m_offset;
float m_factor;
float m_data_float = 0;
bool m_isBigEndian;
bool m_isFloat;
bool m_isSigned;
// Set After everything in signal is filled
bool m_isSignalValid = false;
};
#endif // CANSIGNAL_H
CanMessage::CanMessage(const CanMessage &)
是复制构造函数,显然是用来将一个项目放入列表中的。这是行不通的,因为 QMutex
实际上 不是 可复制的。
你如何解决它取决于很多事情。也许最简单的方法是修改 CanMessage
使其具有动态互斥体(当然是在构造函数中创建的)。
然后为其创建一个复制构造函数,它首先锁定 source 对象互斥量,然后在目标对象中动态分配一个 new 互斥量。
这样,您可以保证旧对象在复制时将是 "clean"(因为您有它的互斥体)并且不会有 "trying to copy an uncopyable member" 问题,因为互斥体本身是 未 复制。有关详细信息,请参阅脚注 (a)
。
以下代码是显示问题的完整简单代码段,如果您将 QMutex m_mutex;
行注释掉,则可以编译:
#include <QList>
#include <QMutex>
#include <iostream>
class Xyzzy {
private:
int m_xyzzy;
//QMutex m_mutex;
public:
Xyzzy() : m_xyzzy(0) {};
Xyzzy(int val) : m_xyzzy(val) {};
};
int main() {
QList<Xyzzy> myList;
Xyzzy plugh;
myList.push_back(plugh);
return 0;
}
一旦您取消注释该行,编译器就会正确地抱怨:
error: use of deleted function 'Xyzzy::Xyzzy(const Xyzzy&)'
(a) 在解决问题方面,您可以这样做:
#include <QList>
#include <QMutex>
#include <iostream>
class Xyzzy {
private:
int m_xyzzy;
QMutex *m_mutex; // Now a pointer
public:
Xyzzy() : m_xyzzy(0) {
m_mutex = new QMutex(); // Need to create in constructor.
std::cout << "constructor " << m_mutex << '\n';
};
~Xyzzy() {
std::cout << "destructor " << m_mutex << '\n';
delete m_mutex; // Need to delete in destructor.
}
Xyzzy(const Xyzzy &old) {
old.m_mutex->lock();
m_mutex = new QMutex(); // Need to make new one here.
std::cout << "copy constructor from " << old.m_mutex
<< " to " << m_mutex << '\n';
old.m_mutex->unlock();
}
};
int main() {
QList<Xyzzy> myList;
Xyzzy plugh;
myList.push_back(plugh);
return 0;
}
根据以下测试运行:
constructor 0x21c9e50
copy constructor from 0x21c9e50 to 0x2fff2f0
destructor 0x21c9e50
destructor 0x2fff2f0
在实际代码中,我可能会选择智能指针而不是原始 new/delete
调用,但这只是为了说明这个概念。此外,您需要处理所有其他可能性,这些可能性根据 three/five/whatever-comes-next 的规则从现有对象创建新对象,目前(从内存中)仅限于复制分配成员 Xyzzy &operator=(const Xyzzy &old)
.
我正在使用 Qt5 构建应用程序。我的程序构建并运行良好,但访问数据结构的两个线程之间存在冲突。我有一个 CanMessage 对象的 QList,我想使用 QMutex 保护其中的一些数据。但是,一旦我将 QMutex 添加到我的 class 定义中,我就会收到错误消息:
QList.h: `error: C2280:
'CanMessage::CanMessage(const CanMessage &)': attempting to reference a deleted function`.
这是我的 canmessage.h
文件:
#ifndef CANMESSAGE_H
#define CANMESSAGE_H
#include <QObject>
#include <QMutex>
#include "cansignal.h"
class CanMessage
{
public:
CanMessage();
/* snip - public function prototypes */
private:
/* snip - private prototypes and data */
QMutex m_messageMutex;
};
#endif // CANMESSAGE_H
和cansignal.h
:
#ifndef CANSIGNAL_H
#define CANSIGNAL_H
#include <QObject>
#include <QDebug>
#include <QByteArray>
class CanSignal
{
public:
CanSignal();
CanSignal(QString &signalName, quint8 &signalLength, quint8 &signalStartBit,
float &offset, float &factor, bool &isBigEndian, bool &isFloat, bool &isSigned)
{
this->m_name = signalName;
this->m_length = signalLength;
this->m_startBit = signalStartBit;
this->m_offset = offset;
this->m_factor = factor;
this->m_isBigEndian = isBigEndian;
this->m_isFloat = isFloat;
this->m_isSigned = isSigned;
}
bool setName(QString &signalName);
bool setBitLength(quint8 &length);
bool setStartBit(quint8 &startBit);
bool setOffset(float &offset);
bool setFactor(float &factor);
bool setEndianess(bool &isBigEndian);
bool setIsFloat(bool &isFloat);
bool setIsSigned(bool &isSigned);
void setValid();
void setInvalid();
void setEngineeringData(float data);
QString getName();
quint8 getBitLength();
quint8 getStartBit();
float getOffset();
float getFactor();
float getData();
bool isBigEndian();
bool isFloat();
bool isSigned();
bool getSignalValidity();
private:
QString m_name;
quint8 m_length;
quint8 m_startBit;
float m_offset;
float m_factor;
float m_data_float = 0;
bool m_isBigEndian;
bool m_isFloat;
bool m_isSigned;
// Set After everything in signal is filled
bool m_isSignalValid = false;
};
#endif // CANSIGNAL_H
CanMessage::CanMessage(const CanMessage &)
是复制构造函数,显然是用来将一个项目放入列表中的。这是行不通的,因为 QMutex
实际上 不是 可复制的。
你如何解决它取决于很多事情。也许最简单的方法是修改 CanMessage
使其具有动态互斥体(当然是在构造函数中创建的)。
然后为其创建一个复制构造函数,它首先锁定 source 对象互斥量,然后在目标对象中动态分配一个 new 互斥量。
这样,您可以保证旧对象在复制时将是 "clean"(因为您有它的互斥体)并且不会有 "trying to copy an uncopyable member" 问题,因为互斥体本身是 未 复制。有关详细信息,请参阅脚注 (a)
。
以下代码是显示问题的完整简单代码段,如果您将 QMutex m_mutex;
行注释掉,则可以编译:
#include <QList>
#include <QMutex>
#include <iostream>
class Xyzzy {
private:
int m_xyzzy;
//QMutex m_mutex;
public:
Xyzzy() : m_xyzzy(0) {};
Xyzzy(int val) : m_xyzzy(val) {};
};
int main() {
QList<Xyzzy> myList;
Xyzzy plugh;
myList.push_back(plugh);
return 0;
}
一旦您取消注释该行,编译器就会正确地抱怨:
error: use of deleted function 'Xyzzy::Xyzzy(const Xyzzy&)'
(a) 在解决问题方面,您可以这样做:
#include <QList>
#include <QMutex>
#include <iostream>
class Xyzzy {
private:
int m_xyzzy;
QMutex *m_mutex; // Now a pointer
public:
Xyzzy() : m_xyzzy(0) {
m_mutex = new QMutex(); // Need to create in constructor.
std::cout << "constructor " << m_mutex << '\n';
};
~Xyzzy() {
std::cout << "destructor " << m_mutex << '\n';
delete m_mutex; // Need to delete in destructor.
}
Xyzzy(const Xyzzy &old) {
old.m_mutex->lock();
m_mutex = new QMutex(); // Need to make new one here.
std::cout << "copy constructor from " << old.m_mutex
<< " to " << m_mutex << '\n';
old.m_mutex->unlock();
}
};
int main() {
QList<Xyzzy> myList;
Xyzzy plugh;
myList.push_back(plugh);
return 0;
}
根据以下测试运行:
constructor 0x21c9e50
copy constructor from 0x21c9e50 to 0x2fff2f0
destructor 0x21c9e50
destructor 0x2fff2f0
在实际代码中,我可能会选择智能指针而不是原始 new/delete
调用,但这只是为了说明这个概念。此外,您需要处理所有其他可能性,这些可能性根据 three/five/whatever-comes-next 的规则从现有对象创建新对象,目前(从内存中)仅限于复制分配成员 Xyzzy &operator=(const Xyzzy &old)
.