Можно ли испустить сигнал от деструктора объекта в Qt?

Когда объект, производный от QObject, разрушается, нормально ли выпустить сигнал из его деструктора? Я попробовал это и, похоже, работает, но я не уверен, что это должно быть сделано.

Например, этот код

class MyClass : public QObject {
signals:
    void mySignal(const QString &str);
public:
    QString myString;
    ~MyClass() { emit mySignal(myString); }
}

передаст ссылку на const для объекта, который может быть вне области видимости к моменту выполнения подключенного слота.

Ответ 1

Выбросы, как правило, прекрасны (QObject делает это тоже с "разрушенным" сигналом), включая случай как ваш. Когда соединение является прямым, строка все еще жива. И когда это QueuedConnection, строка сначала копируется в цикл событий.

Ответ 2

Если вы спросите, все в порядке: да, это не вызовет никаких проблем.

Если вы спросите, есть ли вообще безопасная вещь в Qt? Определенно небезопасно. Вы должны быть очень внимательны, что вы делаете, если испускаете деструктор и хорошо разбираетесь в системе событий Qt.

Помните, что когда d QObject descendant разрушает, он отключает все сигналы, поэтому у разрушенного объекта больше нет вызовов на свои слоты? Ну есть улов: порядок уничтожения. Деструктор QObject отключает, и это LAST разрушает, что означает, что в цепочке уничтожения события могут все еще поступать к "полумертвому" объекту, вызывая нарушения доступа при доступе к виртуальным функциям и членам уже разрушенных потомков. Возможность присутствует, если вы используете систему событий, и любое из этих условий выполнено:

  • В многопоточной среде, если объект не разрушен в своем потоке.
  • В многопоточной среде, если цепочка уничтожения объекта запускает запуск processEvents() в любом пути выполнения.
  • В многопоточной среде, если какой-либо объект в другом потоке имеет прямое соединение с этим объектом и не может реагировать на его уничтоженный сигнал в прямом подключении.
  • В однопоточной среде, когда деструкторы отправляют сигналы который может вернуться к объекту в цепочке прямого соединения.

Я называю этот эффект "жизнь во время смерти", а излучение сигналов или запуск любой формы processEvents() (обычно случайно) в деструкторе увеличивает вероятность создания такой ошибки.

Конечно, если вы можете как-то гарантировать, что ни один из существующих или будущих кодов фактически не вызовет каких-либо слотов во время разрушения, его идеальный сейф, чтобы испускать деструктор формы, но очень сложно дать такую ​​гарантию, и я бы советовал просто избегать по возможности.