2011-12-23 10 views
5
// main_pimpl_sample.cpp 
#include "pimpl_sample.hpp" 

using namespace std; 

int main() 
{ 
    pimpl_sample p; 

    return 0; 
} 

// pimpl_sample.cpp 

#include "pimpl_sample.hpp" 

struct pimpl_sample::impl { 
}; 

pimpl_sample::pimpl_sample() 
    : pimpl_(new impl) { 
} 

// pimpl_sample::~pimpl_sample() 
// cause problem if missed 
// {} 


// pimpl_sample.hpp 

#if !defined (PIMPL_SAMPLE) 
#define PIMPL_SAMPLE 

#include <boost/scoped_ptr.hpp> 

class pimpl_sample { 
    struct impl; 
    boost::scoped_ptr<impl> pimpl_; 

public: 
    pimpl_sample(); 
    //~pimpl_sample(); cause problem if missed 
    void do_something(); 
}; 

#endif 


~/Documents/C++/boost $ g++ --version 
g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2 

~/Documents/C++/boost $ g++ -o main_pimpl_sample main_pimpl_sample.cpp pimpl_sample.cpp pimpl_sample.hpp 
In file included from /usr/include/boost/smart_ptr/scoped_ptr.hpp:15:0, 
       from /usr/include/boost/scoped_ptr.hpp:14, 
       from pimpl_sample.hpp:6, 
       from main_pimpl_sample.cpp:2: 
/usr/include/boost/checked_delete.hpp: In function ‘void boost::checked_delete(T*) [with T = pimpl_sample::impl]’: 
/usr/include/boost/smart_ptr/scoped_ptr.hpp:80:9: instantiated from ‘boost::scoped_ptr<T>::~scoped_ptr() [with T = pimpl_sample::impl]’ 
pimpl_sample.hpp:8:20: instantiated from here 
/usr/include/boost/checked_delete.hpp:32:58: error: invalid application of ‘sizeof’ to incomplete type ‘pimpl_sample::impl’ 
/usr/include/boost/checked_delete.hpp:32:58: error: creating array with negative size (‘-0x00000000000000001’) 

La solución al error de compilación anterior es proporcionar manualmente un destructor. El motivo indicado es el siguiente:Debe proporcionar destructor en el PIMPL

, debe recordar definir el destructor manualmente; el motivo es que en el momento en que el compilador genera un destructor implícito, el tipo impl está incompleto, por lo que no se llama a su destructor.

Pregunta> Todavía tengo dificultades para absorber la idea anterior y me gustaría saber un poco detalle por qué tenemos que proporcionar un destructor manual de aquí.

Gracias

Respuesta

7

TL; DR declarar un destructor explícito e implementarlo en un módulo de código (no en el archivo de cabecera).

Si no crea el destructor, el compilador crea un destructor automático vacío en cada unidad de traducción que intenta destruir un objeto de esta clase. Obtendrá un comportamiento equivalente si definió un destructor en línea vacío en el encabezado de la clase.

Esto provoca un error porque el destructor también es responsable de invocar destructores de todos los campos de la clase, que - en orden - necesita la instanciación de la plantilla de método boost::scoped_ptr<impl>::~scoped_ptr();. Esta plantilla, a su vez, no puede ser instanciada a continuación, ya que intenta eliminar un objeto del tipo impl, que sólo se declaró hacia adelante en ese ámbito (y que necesita una definición completa para saber cómo eliminar este objeto.


otoh, si se declara el constructor no en línea en la cabecera, su código sólo se genera en pimpl_sample.cpp, donde también se encuentra la definición de impl, por lo destructor del scoped_ptr se pueden crear instancias con éxito.

Otras unidades de traducción sólo entonces llamada El destructor pimpl_sample es un método externo, por lo que no es necesario generarlo e instanciar scoped_ptr destructor por su cuenta.

+0

He agregado un breve resumen, no dude en editar/revertir. – krlmlr

Cuestiones relacionadas