Pregunta

Por lo general, uso un boost :: scoped_ptr para Pimpl (por una razón porque entonces no recibo sorpresas si olvido tratar con el constructor de copias)

Sin embargo, con las plantillas, no puedo simplemente poner el destructor en el archivo CPP donde el IMP está completamente definido para cumplir con los requisitos del destructor de Scoped_PTR. Funciona de todos modos, pero no estoy seguro de si está garantizado funcionar o simplemente por casualidad. ¿Hay algunas 'mejores prácticas' o estándar? ¿Es Scoped_PTR el mejor puntero inteligente para PIMPLS en clases no cotizables?

template <class T> class C {
public:
    C(){}
    ~C(){}
private:
    boost::scoped_ptr<T> pimpl_;
};
¿Fue útil?

Solución

boost::shared_ptr no requiere una definición completa que no sea en el punto de instanciación, en el constructor, en el caso de un PIMPL. boost::shared_ptr es no Sin embargo, apropiado para el idioma PIMPL, ya que ofrece una semántica muy inesperada (semántica de referencia para asignación o copia); Si realmente quieres la complejidad adicional de un puntero inteligente, boost::scoped_ptr Sería más apropiado (pero requiere una definición completa en el punto en que se instancia su destructor).

Con respecto a las plantillas, no tiene sentido usar el idioma Pimpl para los detalles de implementación del encabezado. En ausencia de export, todos los detalles de implementación de una plantilla de clase deben incluirse en todas partes donde se use la plantilla, por lo que la motivación detrás del idioma Pimpl deja de existir.

Otros consejos

Simplemente sucede que Herb Sutter comenzó a volver a escribir sus Gotws después de mucho tiempo. Uno de los primeros nuevos está relacionado con "firewalls de compilación".

Es posible que desee echar un vistazo:

GOTW #100: Firewalls de compilación (Dificultad: 6/10)

y

GOTW #101: Firewalls de compilación, Parte 2 (Dificultad: 8/10)

Dos años después, entiendo mucho mejor la situación, en aras de mantener relevantes las respuestas de desbordamiento de la pila y actualizado, así es como respondería la pregunta hoy.

La premisa de mi pregunta original es algo defectuosa. La razón para usar el PIMPL-IDIOM es ocultar los detalles de implementación del compilador. Esto se hace almacenando la implementación a través de un puntero opaco (puntero a un tipo de datos declarado pero no definido). Esto puede reducir en gran medida la cantidad de encabezados necesarios por otras unidades de compilación que interactúan con la clase y, por lo tanto, aceleran el tiempo de compilación. En el caso de la plantilla en mi pregunta, se requiere que el tipo T se conozca completamente en el punto de instanciación que en la práctica requiere que el tipo de implicación esté completamente definido donde sea C<ImplType> se usa, lo que claramente no es un ejemplo de Pimpl-Idiom en el sentido clásico del término.

Hay otras razones para mantener datos de clases a través de un puntero privado, por ejemplo, permite una fácil implementación de movimientos y intercambios sin tiros y también es bueno si su clase necesita cumplir con una fuerte garantía de excepción (consulte el idioma Copy and Swap ¿Cuál es el idioma de copia y intercambio?). Por otro lado, agrega una capa de indirección (que a menudo resulta en una fallas en caché) en cada acceso a la implicación y una asignación/desasignación de montón tras la creación y destrucción de la impl. Estos pueden ser sanciones sustanciales de rendimiento, por lo tanto, esta solución no debe considerarse una bala de plata.

Si puede usar C ++ 11, entonces std :: unique_ptr debe usarse en lugar de boost :: scoped_ptr.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top