Сигналы Qt: Передача владения динамически распределяемым аргументом в слот?

Я не знаю, как точно озаглавить этот вопрос, поэтому вот объяснение:

У меня есть собственный виджет, который выдает сигнал с пользовательским объектом, созданным из пользовательского ввода, когда завершает редактирование, например,

void GGActionEditor::finishEditing() {
GGAction act;
// Set up according to user input
emit actionChanged(act);
}

В этом коде получатели, которые подключены к сингалу, могут сохранить копию этого объекта или обработать его любым удобным способом, и виджет может об этом забыть.

Но как справиться с такой ситуацией, когда виджет можно построить Различные типы объектов из класса иерачры? Подобно:

void GGActionEditor::finishEditing() {
GGAction *pAct;
// Create and set up according to user input, e.g.
if (...) pAct = new GGSpecialAction;
else pAct = new SimpleAction;
emit actionChanged(pAct);
}

Как лучше всего справиться с жизненным циклом объекта в такой ситуации? Виджет не может знать, принимает ли какой-либо получатель объект Action. Кроме того, если подключено несколько приемников, никто из них не знает, принял ли другой объект параметр …
В «лучшем» случае это может привести к утечке; но это также может привести к тому, что параметр будет удален несколько раз.

Обновить:
Еще немного информации о моей реальной ситуации, однако я также заинтересован в общих решениях:

Переданный объект будет сохранен получателем и сохранен в доменной модели приложения. Модель позаботится об его удалении позже.
Простое решение состоит в том, чтобы просто обработать этот случай как «простой» случай значения, описанный выше. Однако, если к нему вообще не подключены приемники, объект будет протекать; и нет 100% гарантии, что только 1 получатель будет делать это (в моей реальной логике приложения это будет иметь место, но это не может быть ни проверено, ни применено таким образом).

Я придумал несколько возможных решений и заинтересован в любых комментариях или дополнениях:

  1. Просто надеюсь, что это сработает:
    Предположим, что будет ровно 1 получатель, который принимает параметр. Это может хорошо работать для моего приложения, но я не чувствую себя счастливым
  2. Используйте общий указатель:
    Как сказал Евгений в ответе, shared_ptr (или QSharedPointer) упростил бы это. Любой получатель и отправитель будут использовать общий указатель, поэтому жизненный цикл управляется автоматически. Но это вынуждает мою модель предметной области использовать общий указатель для каждого класса, который содержит такой объект Action. Это плохо вписывается в мою модель, так как эти классы должны агрегировать действие. Общий указатель не подходит для хранения ссылки на объект, который «принадлежит» объекту …
  3. Добавить параметр, указывающий на обгон:
    Добавить bool* к сигналу, который указывает, принял ли какой-либо приемник действие. Получатель знает, что он не сможет его обогнать, если значение будет истинным. Также отправитель знает, должен ли он удалить объект, если его не получил ни один получатель. Но совершенно случайно, какой получатель возьмет объект в порядке поступления. И это портит интерфейс …
  4. Используйте разные сигналы для разных конкретных классов:
    В этом случае слоты приемника могут знать какой конкретный подкласс используется и сделать копию объекта. Но это добавляет дополнительные сигналы / слоты для чего-то, что может быть очень хорошо сделано с использованием иерархии классов … Также copy-c’tor должен быть доступен для каждого подкласса.
  5. Добавить clone метод к классам:
    Аналогично приведенному выше, но только 1 сигнал. Полиморфный clone создаст копию конкретного подкласса.
  6. Используйте специализированный интерфейс вместо сигнала / слота:
    Делать GGIActionReceiver класс и назначить не более 1 экземпляра в GGActionEditor, Этот экземпляр является единственным правомочным объектом, который принимает объект Action. Другие могут все еще сигнализироваться, но они не должны обогнать указатель. Таким образом, отправитель также знает, должен ли объект быть удален (не указан получатель)

0

Решение

Одним из вариантов здесь является использование общего владения через std :: shared_ptr<> или какой-то другой механизм подсчета ссылок. Таким образом, объект будет жить до тех пор, пока это кому-нибудь нужно.

Обычная модель владения Qt не совсем работает, потому что вы не можете быть уверены, сколько пользователей сигналов захотят стать владельцем одного и того же объекта.

В зависимости от вашей логики совместное владение может привести к замкнутым циклам и разрыву тех, которые могут быть вынуждены сделать дырки в абстракции или двух.

Убедитесь, что не смешиваете владение Qt с shared_ptr — ваши QObjects не должны иметь родителей.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]