Наше приложение очень плохо разработано — оно использует оба std::shared_ptr
а также QObject
отношения родитель-ребенок, чтобы управлять некоторыми из наших объектов. Это приводит к segfaults, когда QObject::~QObject
удаляет свои дочерние объекты и ТО shared_ptr
пытается удалить это также.
Мы обсуждали это, но в настоящее время не видим способа исправить это легко, поэтому мне нужно будет использовать несколько грязных хаков, пока мы не исправим это.
Теперь у меня есть std::shared_ptr<MyObject> getMyObjectPtr()
функция. Мне нужно положить результат в QPointer<MyObject>
— QPointers — это слабые указатели, которые просто указывают, удален ли управляемый ими QObject. Я не могу изменить эту функцию каким-либо образом, это сломало бы все приложение.
Я попробовал несколько хаков с пользовательским деалокатором, но это не сработало.
// get the shared_ptr from inacessible API
std::shared_ptr<MyObject> oldPtr(getMyObjectPtr());
// create a new pointer that never deletes it's value
std::shared_ptr<MyObject> newPtr(nullptr, [](MyObject*) {});
// Move pointer from old to new non-deleting ptr
newPtr.swap(oldPtr);
QPointer<MyObject> qptr(newPtr.get());
Однако, таким образом, указатель удаляется после завершения моей функции. Предположительно, пользовательский деалокатор перемещается вместе с данными.
Я не думаю, что есть какое-то хорошее решение этой проблемы, кроме как начать рефакторинг вашего кода, чтобы любой данный объект управлялся через отношения родитель / потомок в стиле QObject, или же shared_ptr<> Подсчет ссылок — но никогда не в одном и том же объекте. Два подхода слишком отличаются друг от друга, чтобы их было легко согласовать.
Тем не менее, одна вещь, которую вы могли бы сделать, чтобы выполнить вышеизложенное без особой редизайна, заключается в следующем: вместо того, чтобы иметь shared_ptr<> что указывает в ваш QObject, сделайте так, чтобы shared_ptr указывал на управляемый shared_ptr подобъект QObject (не основанный на QObject).
То есть вместо этого:
class MyQObject : public QObject
{
public:
MyQObject(int x, int y, int z, QObject * parent)
: QObject(parent), m_x, m_y, m_z {/* empty */}
int getX() const {return m_x;}
int getY() const {return m_y;}
int getZ() const {return m_z;}
private:
int m_x, m_y, m_z;
};
[...]
QObject * parent = new QObject;
shared_ptr<MyQObject> ptr(new MyQObject(1,2,3,parent)); // d'oh! trouble!
сделать что-то вроде этого:
class MyData
{
public:
MyData(int x, int y, int z) : m_x(x), m_y(y), m_z(z)
int getX() const {return m_x;}
int getY() const {return m_y;}
int getZ() const {return m_z;}
private:
int m_x, m_y, m_z;
};
class MyQObject : public QObject
{
public:
MyQObject(int x, int y, int z, QObject * parent)
: QObject(parent), m_data(make_shared<MyData>(x,y,z)) {/* empty */}
int getX() const {return m_data->getX();}
int getY() const {return m_data->getY();}
int getZ() const {return m_data->getZ();}
shared_ptr<MyData> getData() {return m_data;}
private:
shared_ptr<MyData> m_data;
};
[...]
QObject * parent = new QObject;
QObject * myObj = new MyQObject(1,2,3,parent));
shared_ptr<MyData> ptr(myObj->getData()); // no problem!
Таким образом, ваш код в стиле Qt имеет доступ как к QObject, так и к MyData, а код в стиле shared_ptr имеет доступ к MyData. (Конечно, если ваш код в стиле shared_ptr также нуждается в доступе к самому QObject, вам, вероятно, не повезло, поскольку Qt решит, когда и где удалить QObject, и не будет учитывать семантику shared_ptr)
Других решений пока нет …