aviso do compilador GNU “classe tem funções virtuais, mas destructor não-virtual”

StackOverflow https://stackoverflow.com/questions/127426

  •  02-07-2019
  •  | 
  •  

Pergunta

defini uma interface em C ++, isto é, uma classe que contém funções virtuais única puros.

Eu quero proibir explicitamente os usuários da interface para excluir o objeto através de um ponteiro para a interface, então eu declarou um destruidor protegidos e não-virtual para a interface, algo como:

class ITest{
public:
    virtual void doSomething() = 0;

protected:
    ~ITest(){}
};

void someFunction(ITest * test){
    test->doSomething(); // ok
    // deleting object is not allowed
    // delete test; 
}

O compilador GNU me dá um aviso dizendo:

classe 'ITest' tem funções virtuais, mas destructor não-virtual

Uma vez que o processo de destruição é protegido, qual é a diferença em ter ele virtual ou não-virtual?

Você acha que esse aviso pode ser ignorado ou silenciado com segurança?

Foi útil?

Solução

É mais ou menos um erro no compilador. Note-se que em versões mais recentes do compilador este aviso não são jogados (pelo menos em 4.3 não faz). Tendo o destruidor de ser protegidos e não-virtual é completamente legítimo em seu caso.

aqui para um excelente artigo por Herb Sutter sobre o assunto. Do artigo:

Orientação n. 4: A classe base destrutor deve ser pública e virtual ou protegido e não virtual

Outras dicas

Alguns dos comentários sobre esta resposta relacionar com uma resposta antes que eu dei, o que estava errado.

A protegido meio destructor que só pode ser chamado de uma classe base, não através de exclusão. Isso significa que um ITest * não podem ser directamente eliminados, apenas uma classe derivada pode. A classe derivada pode muito bem querer um destrutor virtual. Não há nada de errado com seu código em tudo.

No entanto, desde que você não pode localmente desativar um aviso em GCC, e você já tem uma vtable, você poderia considerar apenas fazendo o de qualquer maneira virtual destructor. Vai custar-lhe 4 bytes para o programa (não por instância da classe), no máximo. Desde que você pode ter dado sua classe derivada um dtor virtual, você pode achar que não lhe custa nada.

Se você insistir em fazer isso, vá em frente e passar -Wno-non-virtual-dtor a GCC. Este aviso não parece ser ativado por padrão, então você deve ter habilitado com -Wall ou -Weffc++. No entanto, eu acho que é um aviso útil, porque na maioria das situações isso seria um erro.

É uma classe de interface, por isso é razoável que você não deve objetos de exclusão implementar essa interface via essa interface. Um caso comum de que é uma interface para objetos criados por uma fábrica que deve ser devolvido à fábrica. (Tendo objetos contêm um ponteiro para sua fábrica pode ser muito caro).

Eu concordo com a observação de que o GCC está lamentando. Em vez disso, ele deve simplesmente avisar quando você exclui um * ITest. É aí que as mentiras de perigo real.

A minha opinião pessoal é que você está fazendo a coisa correta e o compilador está quebrado. Eu desativar o aviso (localmente no arquivo que define a interface) se possível,

Eu acho que eu uso este padrão (pequeno 'p') muito. Na verdade eu acho que é mais comum para os meus interfaces para ter dtors protegidos do que é para que eles tenham as públicas. No entanto, eu não acho que ele é realmente tão comum um idioma (ele não é falado sobre isso muito) e eu acho que para trás quando o aviso foi adicionado ao GCC era apropriado para tentar impor o 'dtor mais velhos devem ser virtual, se você tem regra funções virtuais. Pessoalmente eu atualizado que regra para 'dtor deve ser virtual, se você tem funções virtuais e usuários desejam ser capaz de excluir instâncias da interface através da interface então o dtor devem ser protegidos e não virtuais' há séculos;)

Se o destruidor é virtual que garante que o destruidor de classe base também é chamado de frente fazendo a limpeza, caso contrário, alguns vazamentos podem resultar de que o código. Portanto, você deve certificar-se de que o programa não tem tais advertências (prefferably há avisos em tudo).

Se você tivesse de código em um dos métodos de ITest que tentaram delete em si (uma má idéia, mas legal), destruidor da classe derivada não seria chamado. Você ainda deve fazer o seu processo de destruição virtual, mesmo se você nunca pretende excluir uma instância derivada através de um ponteiro de classe base.

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