Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > [QT] Почему нельзя удалить объект в слоте?


Автор: null56 18.12.2008, 11:36
Ну собственно вопрос стоит так:
1) связываю сигнал от объекта с обработчиком
2) в случае неудачи вызывается соответствующий слот
3) хочу удалить вызывающий объект из этого слота...

Ругается и если delete ((SslSocket *)sender()) и если удаляю сохранненый указатель на этот объект
Как можно удалить объект из слота, который он вызвал? 

Добавлю лишь:
1) что этот слот связан с несколькими сигналами
2) объект создается динамически

Заранее благодарен

Добавлено через 6 минут и 4 секунды
хотя sender()->deleteLater() помог... Это корректно? он динамический объект точно удалил, я это проверил в деструкторе этого объекта?

Автор: SABROG 18.12.2008, 11:59
Да deleteLater() хороший вариант, т.к. объект удалится после возвращения в eventloop. И его можно вызывать многократно безопасно, например, если на один слот приходит несколько сигналов. Тролли честно предупреждают, что при использовании sender() надо быть осторожным с удалением объекта если к одному слоту подключено несколько сигналов, а также о том, что указатель, который возвращает sender не одно и то же, что и this. Т.е. при каждом попадании в слот указатель возвращаемый sender'ом может быть разным и валидным только пока слот выполняется, пока объект существует и пока сигнал законнекчен к слоту. Но это, если я правильно все понял.

Автор: null56 18.12.2008, 12:22
Просто вот чего я пытаюсь сделать....

Код

...
connect(p_new_client_connection, SIGNAL(encrypted()), this, SLOT(ready()));
connect(p_new_client_connection, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(fail()));
connect(p_new_client_connection, SIGNAL(stateChanged (QAbstractSocket::SocketState)), this, SLOT(fail()));
sleep(5);
qDebug("Start encryption");
p_new_client_connection->startEncrypt(mSslCertificate, mSslKey);
...


Далее функции обработки

ready()
Код

void SslServer :: ready()            /*private slot*/
{
    qDebug("success");
    qDebug("Emited socket descriptor: %d", ((SslSocket *)sender())->socketDescriptor());
    qDebug("Mode: %d", ((SslSocket *)sender())->mode());
    qDebug("State: %d", ((SslSocket *)sender())->state());
}


И функция изменения состояния:
Код

void SslServer :: fail()            /*private slot*/
{
    const SslSocket * p_sender_socket = (SslSocket *)sender();
    qDebug("Fail");
    qDebug("Emited socket descriptor: %d", p_sender_socket->socketDescriptor());
    qDebug("Mode: %d", p_sender_socket->mode());
    qDebug("State: %d", p_sender_socket->state());
    QList<QSslError> list_errors;
    list_errors = p_sender_socket->sslErrors();
    qDebug("errors count: %d", list_errors.count());
    sender()->deleteLater();
}


После создания нового подключения, я соединяю сигналами с нужными слотами в таймауте рву соединение со стороны клиента и запускаю startServerEnclytion... Получается, что объект не удалится, пока не отработают все его сигналы, потому что вывод в консоль показывает, дважды вызов на событие stateChange()

Вывод в консоль
Код

new connection
Start encryption

Fail
Emited socket descriptor: 10
Mode: 2
State: 6
errors count: 0

Fail
Emited socket descriptor: 10
Mode: 2
State: 0
errors count: 0
DESTROY    !!!! ЭТО ВЫЗЫВАЕТСЯ В ДЕСТРУКТОРЕ ОБЪЕКТА SslSocket


Автор: SABROG 18.12.2008, 12:41
Первый раз приходит QAbstractSocket::ClosingState, типа дожидаемся завершения получения данных, если такие есть и закрываемся. Второй раз приходит QAbstractSocket::UnconnectedState, типа закрылись.

Думается мне что все-таки придется делать два слота и прописать в них соотв. параметры, чтобы отслеживать состояние сокета и удалять объект только при приходе QAbstractSocket::UnconnectedState.

Кстати интересно, при таком подходе будет утечка памяти или нет.

Код

connect(p_new_client_connection, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(fail()));


Ведь если сигнал пихает каждый раз параметр в стек, а этот стек слот не очищает при retn считая, что у него нет параметров.

Автор: null56 18.12.2008, 12:43
Сейчас создал метод getMe() {return this;}

Через него сделал в обработчике
disconnect(getMe, 0, this, 0);

После дисконекта ругнулся на QCoreApplication::postEvent: Unexpected null receiver, что в принципе логично наверное...

Цитата

Думается мне что все-таки придется делать два слота и прописать в них соотв. параметры, чтобы отслеживать состояние сокета и удалять объект только при приходе QAbstractSocket::UnconnectedState.


А в одном слоте состояние сокета нельзя проверить разьве?

Добавлено @ 12:48
Слот, я так понял неделимая операция, пока не отработает, другой сигнал его прервать не может... это видно из моего примера

Добавлено @ 12:52
Цитата

стати интересно, при таком подходе будет утечка памяти или нет.

Выделить всёкод C++
1:
    
connect(p_new_client_connection, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(fail()));


Ведь если сигнал пихает каждый раз параметр в стек, а этот стек слот не очищает при retn считая, что у него нет параметров.



Здесь в стек кладется объект QList<QSslError &> - это объект, который занимает память, утечки никак не будет

Просто доступа к этой переменной нет внутри функции, а получить через указатель стека, наверняка можно

Автор: null56 18.12.2008, 13:06
Хотя хз... смотря кто стек чистит... вызывающая или вызываемая. Вот если вызываемая, то он когда не знает ничего об этой переменной, но думаю в qt все продумано, так как если бы он не удалял из стека область памяти, которую занимает эта перменная, то он бы не добрался до адреса возврата, который находится ниже в стеке, так что думаю, чистится все граммотно +
у меня в книжке от создателей написано, что если у сигнала больше параметров, чем у слота, то остальные параметры будут игнорироваться )

Автор: SABROG 18.12.2008, 13:51
Да, что-то я подзабыл ассемблер smile

Автор: null56 18.12.2008, 13:58
Конечно по хорошему надо посмотреть это дело в дебагаре, если не верить книжке, но в самом правильном случае лучше конечно разделить на два разных слота, так и гибче будет

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)