Безопасно ли использовать QObject в качестве члена класса и использовать этот член в качестве контекста для соединения? - PullRequest
4 голосов
/ 12 июля 2019

У меня есть "нормальный" (не производный от qt) класс. Он получает ссылку на QObject. Внутри этого класса я хочу соединить входной сигнал QObject с лямбдой. Пока все хорошо, все работает отлично, за исключением случаев, когда объект моего класса уничтожается перед передачей в QObject. Сигнал от QObject теперь указывает на лямбду, которая больше не существует.

Обычный способ сделать это - мой класс наследует от QObject и передает this в качестве контекста connect. Затем соединения будут автоматически уничтожены кодом Qt, когда мой объект умрет.

Еще один способ решения этой проблемы - сохранить возвращаемый результат соединения, a QMetaObject::Connection, а затем в деструкторе моего класса вызвать QObject::disconnect(resultOfConnect).

Теперь, как я хотел решить это так:

class SomeQtDerivedClass : public QObject {...}

class MyClass
{
public:
    MyClass(SomeQtDerivedClass& qtObject)
    {
        connect(&qtObject, &qtObject::someSignal, &m_QtObject, [](){blahblah})
    }
private:
    QObject m_QtObject;
}

Я не видел, чтобы этот шаблон использовался где-либо, и я не могу найти ничего в официальной документации об этом подходе. Я не хочу наследовать от QObject, если вместо этого я могу использовать композицию. Я не хочу создавать m_QtObject в куче, если я могу создать его в стеке. И я хочу, чтобы соединение было автоматически уничтожено, если мой объект класса был уничтожен до введенного QObject.

Будет ли это работать?

Ответы [ 2 ]

4 голосов
/ 12 июля 2019

Должно работать нормально (конечно, если вы не установите родителя на m_QtObject); m_QtObject уничтожается вашим классом (после предоставленного пользователем деструктора, если таковой имеется), поэтому он почти не отличается от того, если вы наследуете QObject (действительно, базовый класс с многих точек зрения действительно похож на скрытый первый ученик).

При этом я бы использовал QMetaObject::Connection (возможно, завернув его в std::unique_ptr или что-то еще, чтобы получить автоматическое отключение при уничтожении); QObject довольно тяжеловесен, использование его только для использования его функций автоматического разъединения кажется пустой тратой.

2 голосов
/ 12 июля 2019

Это не прямой ответ на вопрос, но он отвечает неправильному представлению @ vuko_zrno.

Наличие QObject в качестве члена (в отличие от QObject *) не гарантирует, что вы распределите стек,Это только гарантирует вам, что QObject будет использовать тот же кусок памяти, что и экземпляр MyClass, владеющий им.

Например, если вы выполните MyClass obj;, тогда и MyClass, и QObject будут в стеке.Но если вы сделаете MyClass * obj = new MyClass;, они оба будут в куче.

Также что-то очень важное, классы Qt интенсивно используют шаблон проектирования pimpl.Это означает, что класс QObject представляет собой просто пустую оболочку, и все его переменные-члены хранятся в другом классе с именем QObjectPrivate.

На практике размер QObject составляет 16 байт в 64-битном режиме, в то время как QObjectPrivate 112 байт.И QObjectPrivate всегда будет выделяться в куче.

Поэтому на практике я не уверен, что наличие QObject против QObject * имеет какое-либо существенное различие.

...