Russian Qt Forum
Май 29, 2024, 13:30 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Удаление указателя внутри слота  (Прочитано 6509 раз)
DS_tm
Гость
« : Ноябрь 13, 2010, 23:46 »

Есть сигнал содержащий в списке параметров указатель на объект (не QObject). Есть несколько не связанных между собой объектов обрабатывающих в своих слотах данный сигнал. Один из слотов использует оператор delete для очистки памяти на которую указывает указатель (сорри за тавтологию). В результате в других слотах происходит ошибка обращения к удаленной памяти. Как можно решить данную проблему?
Записан
vlad-mal
Гость
« Ответ #1 : Ноябрь 14, 2010, 05:39 »

Нормально.

А какое поведение вы бы хотели?

Чтобы не обращаться к удаленному объекту?
Чтобы каждый слот работал со своим экземпляром объекта?
...
?

Цитировать
- Доктор, мне больно когда я так делаю!
- Ну не делайте так!
« Последнее редактирование: Ноябрь 14, 2010, 06:20 от vlad-mal » Записан
DS_tm
Гость
« Ответ #2 : Ноябрь 14, 2010, 13:41 »

Да, я понимаю, что поведение ожидаемое, вопрос в том, возможно ли обойти его.
На вскидку вижу 3 решения проблемы.
1) В каждом слоте проверять, указывает указатель на что-то валидное или на нойс (в рамках С++ я не знаю как это сделать)
2) Заглушить емит сигнала к другим слотам. (самый адекватный вариант на мой взгляд, но в Qt ничего подобного вроде нет)
3) Удостовериться, что слот, удаляющий объект запускается последним (тоже нет механизмов регулирования данной последовательности. Мое предположение, что используется стек (LIFO), то есть чтобы слот обрабатывался последним его нужно приконектить первым, но это очень нестабильный вариант).

в итоге 0 готовых решений)
Записан
BlackTass
Гость
« Ответ #3 : Ноябрь 14, 2010, 13:53 »

сделать его наследником QObject и вызвать deleteLater()?
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #4 : Ноябрь 14, 2010, 14:12 »

DS_tm, обычная практика:
перед обращением к объекту через указатель, делать проверку на нуль:
Код
C++ (Qt)
if (pointer) pointer->method();

сразу после удаления объекта обнулять указатель:
Код
C++ (Qt)
delete pointer;
pointer = 0;
Записан

Юра.
DS_tm
Гость
« Ответ #5 : Ноябрь 14, 2010, 14:14 »

сделать его наследником QObject и вызвать deleteLater()?

К сожалению не вариант, класс из 3th-part библиотеки. В итоге делаю воркераунд вроде того, что вы предложили, коллекционирую
указатели в список и удаляю потом. Удаление происходит по таймауту (время заведомо большее, чем потребуется для обработки всех слотов) либо в деструкторе класса, содержащего данный слот. Оба варианта мне не очень нравятся, думаю переписать с использованием postEvent() и своим евентом, который вызывает очистку списка (собственно deleteLater() так и работает).
Записан
DS_tm
Гость
« Ответ #6 : Ноябрь 14, 2010, 14:16 »

DS_tm, обычная практика:
перед обращением к объекту через указатель, делать проверку на нуль:
Код
C++ (Qt)
if (pointer) pointer->method();

сразу после удаления объекта обнулять указатель:
Код
C++ (Qt)
delete pointer;
pointer = 0;

Этот вариант попробовал сразу, но, как я и думал, результата нет. Причина в том что при emit используется копия указателя для каждого слота и обнуление одной копии ничего не дает для другой.
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #7 : Ноябрь 14, 2010, 15:13 »

покажи код, как посылаешь сигнал и как принимаешь в слоте
Записан

Юра.
vlad-mal
Гость
« Ответ #8 : Ноябрь 14, 2010, 15:20 »

DS_tm, вы так и не описали, что вы хотите:

Вариант 1. При удалении объекта в одном из слотов хотите знать, что объект удален, и не обрабатывать его?

Вариант 2. В каждом из слотов работать с объектом, а удалять по окончании обработки во всех слотах?

~~~~~~~~~~~~~~~~~~~~~~

Можете в классе объекта (или его "обертке") завести статическое поле - счетчик ссылок.

Для варианта 2:
Если нужен второй вариант, то установите его в значение, равное числу слотов, а потом отправляете объект.
В каждом слоте, после использования, перед разрушением объекта уменьшаем счетчик на 1, и если он стал равен нулю - смело удаляем.

Для варианта 1 счетчик устанавливаем в 1.
В слотах перед использованием проверяем, если не ноль - уменьшаем на 1 и используем по полной программе, потом удаляем.
Не забываем о синхронизации.
Записан
vlad-mal
Гость
« Ответ #9 : Ноябрь 14, 2010, 15:21 »

сделать его наследником QObject и вызвать deleteLater()?

К сожалению не вариант, класс из 3th-part библиотеки...
...
Ну так "оберните" этот объект в свой!
Записан
DS_tm
Гость
« Ответ #10 : Ноябрь 14, 2010, 19:34 »

покажи код, как посылаешь сигнал и как принимаешь в слоте

Что-то типа:

Код
C++ (Qt)
class NotQObject
{
...
public:
 void someFunct();
}
 
class emitClass : public QObject
{
...
 signals:
   void mySignal(NotQObject *obj);
}
 
class slotClass1 : public QObject
{
...
public slots:
 void slotMySignal(NotQObject *obj)
 {
   ...
   obj->someFunct();
   ...
 }
}
 
class slotClass2 : public QObject
{
...
public slots:
 void slotMySignal(NotQObject *obj)
 {
   ...
   delete obj;
   ...
 }
}
 

Ну и собственно слоты slotMySignal обоих классов где-то подключены к сигналу mySignal.
Записан
DS_tm
Гость
« Ответ #11 : Ноябрь 14, 2010, 19:50 »

DS_tm, вы так и не описали, что вы хотите:
Вариант 1. При удалении объекта в одном из слотов хотите знать, что объект удален, и не обрабатывать его?
Вариант 2. В каждом из слотов работать с объектом, а удалять по окончании обработки во всех слотах?
<...>

Спасибо, меня устроили оба варианта, Ваши идеи по поводу счетчика ссылок интересны. Правда помимо создания врапера для класса объекта понадобиться еще делать врапер для класса посылающего сигнал (он тоже из внешней библиотеки, а следовательно инерфейс сигнала зафиксирован). Еще мне непонятно зачем Вы предложили использовать статический член, если объектов много то они все будут оперировать одним счетчиком ссылок, что в конечном итоге приведет к суматохе. Не могу не заметить также, что первый вариант тогда не доступен, ибо если делать член нестатичным то, при удалении объекта, к нему уже никак не обратиться. Во-втором же варианте есть небольшая проблема, связанная с необходимостью точно знать, сколько слотов подключено к сигналу, что в принципе не очень то удобно, нужно всегда помнить о счетчике при добавлении/удалении слота для сигнала.
В итоге я думаю все же остановиться на использовании postEvent() функции и очистке списка объектов после обработки всех сигналов. Плюс не надо создавать два класса врапера.
Записан
vlad-mal
Гость
« Ответ #12 : Ноябрь 14, 2010, 19:54 »

Ну, не угадал. Улыбающийся
Обычное дело, когда вопрос задан в форме: "кто первый догадается, что мне нужно?"
Записан
DS_tm
Гость
« Ответ #13 : Ноябрь 15, 2010, 12:03 »

Ну, не угадал. Улыбающийся
Обычное дело, когда вопрос задан в форме: "кто первый догадается, что мне нужно?"
Я просто не вижу смысла особого задавать конкретный вопрос "как сделать что-то, если входные данные такие, а на выходе надо получить это?". Чаще всего для таких вопросов достаточно внимательно посмотреть маны ну или погуглить пару минут.
А тут небольшой брейнстормчик, взгляд на проблему со стороны, все дела. В итоге агрегируя идеи получается нормальное готовое решение. Спасибо большое за участие, приходите еще!  Подмигивающий
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.141 секунд. Запросов: 22.