Pergunta

Existe um objeto da classe QNetworkReply. Há um slot (em algum outro objeto) conectado ao seu sinal concluído (). Os sinais são síncronos (os padrões). Existe apenas um tópico.

Em algum momento, quero me livrar de ambos os objetos. Não há mais sinais ou nada deles. Eu quero que eles vão embora. Bem, pensei, vou usar

delete obj1; delete obj2;

Mas posso realmente? As especificações para ~ QObject dizem:

Excluir um QObject enquanto os eventos pendentes estão esperando para serem entregues pode causar uma falha.

O que são 'eventos pendentes'? Isso pode significar que, enquanto estou chamando meu delete, já existem alguns 'eventos pendentes' a serem entregues e que eles podem causar uma falha e não posso realmente verificar se há algum?

Digamos que eu ligue:

obj1->deleteLater(); obj2->deleteLater();

Para estar seguro.

Mas estou realmente seguro? O deleteLater adiciona um evento que será tratado no loop principal quando o controle chegar lá. Pode haver alguns eventos pendentes (sinais) para obj1 ou obj2 já presentes, esperando para serem tratados no loop principal antes de deleteLater ser tratado? Isso seria muito lamentável. Não quero escrever código verificando o status de 'um pouco excluído' e ignorando o sinal de entrada em todos os meus slots.

Foi útil?

Solução

Excluir QObjects geralmente é seguro (ou seja, na prática normal; pode haver casos patológicos dos quais não estou ciente de atm), se você seguir duas regras básicas:

  • Nunca exclua um objeto em um slot ou método que seja chamado direta ou indiretamente por um sinal (síncrono, tipo de conexão "direto") do objeto a ser excluído. Por exemplo. se você tem uma classe Operation com um sinal Operation :: ended () e um slot Manager :: operationFinished (), você não quer deletar o objeto de operação que emitiu o sinal naquele slot. O método que emite o sinal terminado () pode continuar acessando "this" após a emissão (por exemplo, acessando um membro), e então operar em um ponteiro "this" inválido.

  • Da mesma forma, nunca exclua um objeto no código que é chamado de forma síncrona do manipulador de eventos do objeto. Por exemplo. não exclua um SomeWidget em seu SomeWidget :: fooEvent () ou em métodos / slots que você chamar de lá. O sistema de eventos continuará operando no objeto já excluído -> Crash.

Ambos podem ser difíceis de rastrear, já que os rastros de retorno geralmente parecem estranhos (como travamento ao acessar uma variável de membro POD), especialmente quando você tem cadeias de sinal / slot complicadas onde uma exclusão pode ocorrer vários passos abaixo originalmente iniciada por um sinal ou evento do objeto que é excluído.

Esses casos são o caso de uso mais comum para deleteLater (). Ele garante que o evento atual possa ser concluído antes que o controle retorne ao loop de eventos, que exclui o objeto. Outra, que geralmente encontro a melhor maneira, é adiar toda a ação usando uma conexão enfileirada / QMetaObject :: invokeMethod (..., Qt :: QueuedConnection).

Outras dicas

As próximas duas linhas de seus documentos referidos dizem a resposta.

De ~ QObject ,

Excluir um QObject enquanto os eventos pendentes estão esperando para serem entregues pode causar um travamento.Você não deve excluir o QObject diretamente se ele existir em um thread diferente daquele em execução no momento. Use deleteLater () em vez disso, o que fará com que o loop de eventos exclua o objeto depois que todos os eventos pendentes forem entreguespara isso.

Diz especificamente para não excluirmos de outros tópicos.Como você tem um único aplicativo encadeado, é seguro excluir QObject.

Caso contrário, se você tiver que excluí-lo em um ambiente multi-threaded, use deleteLater() que excluirá seu QObject assim que o processamento de todos os eventos for concluído.

Você pode encontrar a resposta para sua pergunta lendo sobre uma das Regras de objeto Delta que afirma isso:

Sinal de segurança (SS).
Deve ser seguro para métodos de chamada no objeto, incluindo o destruidor, de dentro de um slot sendo chamado por um de seus sinais.

Fragmento:

Basicamente, o QObject suporta ser excluído durante a sinalização. A fim de tirar vantagem disso você só tem que certifique-se de que seu objeto não tente acessar qualquer um de seus próprios membros após sendo excluído. No entanto, a maioria do Qt objetos não são escritos desta forma, e não há nenhum requisito para que sejam ou. Por esse motivo, é recomendado que você sempre ligue deleteLater () se você precisar excluir um objeto durante um de seus sinais, porque as chances são de que "deletar" irá basta travar o aplicativo.

Infelizmente, nem sempre é claro quando você deve usar ‘delete’ vs deleteLater (). Ou seja, não é sempre óbvio que um caminho de código tem um fonte de sinal. Muitas vezes, você pode ter um bloco de código que usa ‘delete’ em alguns objetos que são seguros hoje, mas em algum ponto no futuro este mesmo bloco de código acaba sendo invocado de uma fonte de sinal e agora de repente seu aplicativo está travando. A única solução geral para este problema é use deleteLater () o tempo todo, mesmo se à primeira vista parecer desnecessário.

Geralmente considero as Regras do objeto Delta uma leitura obrigatória para todos os desenvolvedores Qt. É um excelente material de leitura.

Até onde eu sei, isso é principalmente um problema se os objetos existirem em threads diferentes.Ou talvez enquanto você está realmente processando os sinais.

Caso contrário, deletar um QObject irá primeiro desconectar todos os sinais e slots e remover todos os eventos pendentes.Como uma chamada para desconectar () faria.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top