2010-05-17 9 views
13

No entiendo el propósito de boost :: checked_delete. La documentación dice:Propósito del impulso :: checked_desert

el estándar de C++ permite, en 5.3.5/5, punteros a tipos de clases incompletas a ser eliminados con un delete-expresión. Cuando la clase tiene un destructor no trivial , o un operador de clase específico delete, el comportamiento es undefined. Algunos compiladores emiten una advertencia cuando se borra un tipo incompleto , pero desafortunadamente, no todos hacen, y los programadores a veces ignoran o deshabilitan las advertencias.

la función y clase suministrado plantillas se pueden utilizar para evitar estos problemas , ya que requieren un tipo completo , y causar un error de compilación lo contrario.

Así estándar de C++ le permite borrar tipos incompletas, lo que provoca un comportamiento indefinido si el tipo tiene un destructor no trivial. ¿Qué? ¿Cómo puede un tipo incompleto tener algún destructor? ¿No es un tipo incompleto solo un prototipo?

+0

¿Podría tener esto algo que ver con rebanar? http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c – Cogwheel

Respuesta

16

El ejemplo más común de un tipo incompleto es uno que sólo ha sido declarado:

// this file does not include the definition of foo 

class foo; 

void bad(foo *f) 
{ 
    delete f; // undefined behavior if there exists foo::~foo 
} 

En realidad, la definición de foo puede tener este aspecto:

class foo 
{ 
public: 
    ~foo() { ... }; 
}; 

Pero si la parte superior el código no ha "visto" la definición de clase y solo ve la declaración de clase, el código se compilará.

+0

¿Cómo es posible * exigir * un tipo completo en una plantilla de clase? –

+3

'checked_delete' intenta llamar a' sizeof' en el tipo, y aparentemente eso causa un error del compilador si el tipo está incompleto. – Channel72

+0

@ Channel72: ¿Por casualidad sabes por qué C++ no define esto como un error de compilación de todos modos? –

2

C++ le permite usar delete en variables que en ese momento son punteros a tipos incompletos.

struct S; // incomplete 

int main() { 
    S* s = NULL; 
    delete s; // legal 
} 

El compilador no sabe en ese momento lo que realmente es S. Si resulta que S tiene un destructor no trivial, entonces no es necesario que el compilador detecte ese problema.

Hablando en términos prácticos, lo que probablemente sucede es que cuando el compilador encuentra la instrucción delete en un tipo incompleto, rellena una llamada a lo que espera que sea el compilador ordinario del generador-generador predeterminado del tipo. Y si eso es lo que resulta el destructor, entonces todo está bien. Pero si resulta que S tiene un destructor no trivial, o si proporciona su propio método especial de eliminación, entonces lo que el compilador completó antes será incorrecto. El compilador, sin embargo, permite suponer que compiló correctamente la instrucción delete y nunca mira hacia atrás. Cuando esa suposición es incorrecta, obtendrá un comportamiento indefinido.

La función Boost asegura que se llama solo en tipos completos, evitando así el comportamiento indefinido que puede ocurrir en tipos incompletos.

4

considerar lo siguiente:

foo.h:

#ifndef Foo_H 
#define Foo_H 
#include <boost/scoped_ptr.hpp> 
#include <boost/utility.hpp> 

class Foo : private boost::noncopyable 
{ 
public: 
    Foo(); 
    ~Foo(); 

    void do_something_interesting(); 

private: 
    class Impl; // incomplete type 
    boost::scoped_ptr<Impl> impl; 
}; 

#endif 

Foo.CPP:

#include "Foo.h" 
#include <string> 
#include <iostream> 

class Foo::Impl 
{ 
public: 
    Impl() : name("Foo::Impl") 
    {} 

    void say_hi() 
    { std::cout << name << " says hi!" << std::endl; } 

    std::string name; 
}; 

Foo::Foo() 
: impl(new Impl) 
{} 

Foo::~Foo() 
{} 

void Foo::do_something_interesting() 
{ impl->say_hi(); } 

Dada esta (artificial) ejemplo, no se puede inline o bien Foo::Foo o Foo::~Foo porque el tipo es incompleta. Al definir ambos en un contexto donde el tipo Foo::Impl es un tipo completo, puede eliminar el tipo de forma segura. boost::checked_delete hace esta verificación de seguridad para usted, y es simplemente un costo en tiempo de compilación. Si alinea Foo::~Foo u omitirlo por completo, obtendrá un error de boost::checked_delete donde quiera que intente destruir una instancia de Foo.

Cuestiones relacionadas