CanMessage::CanMessage(const CanMessage &)
- это конструктор копирования, который, очевидно, используется для помещения элемента в список. Это не сработает, поскольку QMutex
не на самом деле копируемый.
Как вы решите это, зависит от многих вещей. Возможно, самым простым способом было бы изменить CanMessage
так, чтобы он имел динамический мьютекс (конечно, созданный в конструкторе).
Затем создайте для него конструктор копирования, который сначала блокирует мьютекс объекта source , а затем динамически выделяет новый мьютекс в целевом объекте.
Таким образом, вы можете гарантировать, что старый объект будет "чистым" при копировании (потому что у вас есть его мьютекс), и не будет проблемы "попытки скопировать некопируемый элемент", так как сам мьютекс не скопировано. Подробнее см. Сноску (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 0x21c9ec0
destructor 0x21c9e50
destructor 0x21c9ec0
В реальном коде я бы, вероятно, выбрал умные указатели, а не необработанные new/delete
вызовы, но это только для иллюстрации концепции. Кроме того, вам нужно будет обработать все другие возможности, которые создают новый объект из существующего, в соответствии с правилом «три / пять / все, что приходит дальше», в настоящее время (из памяти) ограничено элементом назначения копирования Xyzzy &operator=(const Xyzzy &old)
.