Excluindo objeto com destructor privada
-
05-07-2019 - |
Pergunta
Como isso é possível que ele é permitido objeto de exclusão com destructor privada no código a seguir? Eu reduzi programa real para o exemplo a seguir, mas ainda compila e obras.
class SomeClass;
int main(int argc, char *argv[])
{
SomeClass* boo = 0; // in real program it will be valid pointer
delete boo; // how it can work?
return -1;
}
class SomeClass
{
private:
~SomeClass() {}; // ! private destructor !
};
Solução
Você está tentando excluir objeto do tipo classe incompleta. C ++ Padrão diz que você vai ter um comportamento indefinido, neste caso (5.3.5 / 5):
Se o objecto a ser suprimida tem tipo de classe incompleta no ponto de eliminação e a classe completa tem um destruidor não trivial ou uma função desatribuição, o comportamento é indefinido.
Para detectar tais casos, você pode usar boost::checked_delete
:
template<typename T>
inline void checked_delete( T* p )
{
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete p;
}
Outras dicas
Este código provoca um comportamento indefinido (UB). É UB em C ++ para delete
um objecto do tipo incompleto tendo um destruidor não trivial. E em seu código do tipo SomeClass
é incompleta no ponto de delete
, e tem um destrutor não-trivial. Compiladores normalmente emitir um aviso sobre isso, já que em C ++ formalmente esta não é uma violação de restrição.
Assim, estritamente falando, seu código não faz "trabalho". Ele simplesmente compila e faz algo indefinido quando for executado.
O compilador não é apenas necessário para pegar esse erro. A razão para isto é que este poderia ser perfeitamente bem se o seu objeto tem um trivial destructor. O compilador não tem como saber que tipo de destruidor este tipo acabará por ter, por isso não posso dizer com certeza se este é um erro ou não.
Como o tipo SomeClass
não está completamente declarou ao invocar operator delete
.
A exclusão de tal ponteiro é um comportamento indefinido, mas na prática a maioria dos compiladores só iria liberar a memória (se o ponteiro foi não-NULL) e não chamar o destruidor.
Por exemplo, g ++ vai lhe dar um aviso sobre esse problema:
foo.cpp: In function 'int main(int, char**)':
foo.cpp:6: warning: possible problem detected in invocation of delete operator:
foo.cpp:5: warning: 'boo' has incomplete type
foo.cpp:1: warning: forward declaration of 'struct SomeClass'
foo.cpp:6: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.