É seguro `delete this`? [duplicado]
-
23-08-2019 - |
Pergunta
Esta questão já tem uma resposta aqui:
- é excluir esta permitido? 10 respostas
Em meus testes básicos iniciais é perfeitamente seguro fazê-lo. No entanto, tem-me que tentar manipular this
mais tarde, em uma função que delete
s this
poderia ser um erro de execução. Isso é verdade, e é normalmente seguro para delete this
? ou existem apenas alguns casos em que é seguro?
Solução
delete this
é legal e faz o que você esperaria: chama destruidor de sua classe e liberar a memória subjacente. Depois delete this
retornos, o valor do ponteiro this
não mudança, por isso é agora um apontador pendente que deve não ser dereferenced. Isso inclui dereferencing implícita usando variáveis ??membro da classe.
Ele é normalmente encontrado nas classes contou-referência que, quando o ref-contagem é diminuída para 0, o DecrementRefCount()
/ Release()
/ whatever membro função chama delete this
.
delete this
é normalmente considerado uma forma muito ruim para muitas razões. É fácil de variáveis ??de membro acidentalmente Access depois delete this
. código chamador pode não perceber o seu objeto tem auto-destruiu.
Além disso, delete this
é um "cheiro de código" que seu código pode não ter uma estratégia simétrica para a posse do objeto (quem aloca e quem apaga). Um objeto não poderia ter alocado-se com new
, assim que chamar meios delete this
que a classe A está alocando um objeto, mas a classe B é mais tarde liberando-[auto].
Outras dicas
É seguro excluir "isto", enquanto ele é essencialmente a última operação no método. Na verdade várias APIs de nível profissional fazê-lo (ver implementação CComObject de ATL para um exemplo).
O único perigo está tentando acessar quaisquer outros dados de membros depois de chamar "excluir este". Este é certamente inseguro.
Apagar esta é perfeitamente legal como outros já mencionados. É arriscado, por uma razão adicional que ainda não foi mencionado - você está assumindo que o objeto foi alocado no heap. Isso pode ser difícil de garantia, embora no caso de implementações de contagem de referência, geralmente não é um problema.
Mas não fazê-lo no processo de destruição!
Como dito por outros, excluir esta é uma expressão válida, mas para que ele seja seguro você tem que garantir que o objeto nunca é instanciado na pilha.
Uma maneira de fazer isso é fazer com que tanto o construtor eo destruidor privado e reforçar a criação do objeto através de uma função de fábrica de classe que cria o objeto na pilha e retorna um ponteiro para ele. A fábrica de classe pode ser uma função membro estático ou uma função amigo. Limpeza pode ser feito através de um método Delete () sobre o objeto que faz o "excluir este". COM objetos basicamente trabalhar desta forma, exceto que, além disso, são referência contou com a "excluir este" ocorre quando a contagem de referência é diminuída a zero.
Sim. Deve ser perfeitamente bem. "Isto" é apenas um ponteiro. Qualquer ponteiro vai fazer por exclusão. As informações sobre como excluir um objeto está contido nos registros da pilha. Isto é como IUnknown :: Release () é normalmente implementado em COM objetos.
apagar isso pode causar um problema quando você tem subclasses do objeto que você está excluindo. Lembre-se de construção começa a partir de cima para baixo e de exclusão começa a partir-se inferior. Então, se eliminar este está no meio da hierarquia você basicamente perdeu todos os objetos abaixo desta classe particular.
excluir este é muito útil quando você está implementando uma referência contados objeto, um exemplo de que é as classes COM.
Leia para uma discussão semelhante. Seu entendimento é direito na medida em que não trabalho, é necessário, e pode ser perigoso desde que você não pode acessar esta tarde.
Sim Legal
Seguro Nenhum
Se você está herdando de uma classe base e deu excluir esta na função de classe base, usando ponteiro classe derivada irá causar um acidente. Por exemplo:
class Base
{
virtual void Release()
{
delete this;
}
}
class Derived : public Base
{
void Foo()
{
...
}
}
main()
{
Base *ptrDerived = new Derived();
ptrDerived->release();
ptrDerived->Foo() //Crash
}