2009-07-24 11 views
17

Una de las cosas que me ha resultado confuso mientras aprendía C++ (y Direct3D, pero eso hace algún tiempo) es cuando debería usar un miembro de puntero en una clase. Por ejemplo, puedo usar una declaración no puntero:C++: cuándo debería usar un miembro de puntero en una clase

private: 
    SomeClass instance_; 

O podría usar una declaración de puntero

private: 
    Someclass * instance_ 

y luego usar nueva() sobre ella en el constructor.

Entiendo que si SomeClass podría derivarse de otra clase, un objeto COM o es un ABC, entonces debería ser un puntero. ¿Hay alguna otra guía que deba conocer?

Respuesta

17

Un puntero tiene las siguientes ventajas:

a) Se puede hacer una inicialización perezosa, que significa a init/crear el objeto sólo se corta antes de que el primer uso real.

b) El diseño: si utiliza punteros para miembros de un tipo de clase externo, puede colocar una declaración directa por encima de su clase y no necesita incluir los encabezados de ese tipo en su encabezado, en lugar de eso incluye los encabezados de terceros en su .cpp, que tiene la ventaja de reducir el tiempo de compilación y evita los efectos secundarios al incluir demasiados encabezados.

class ExtCamera; // forward declaration to external class type in "ExtCamera.h" 

class MyCamera { 
public: 
    MyCamera() : m_pCamera(0) { } 

    void init(const ExtCamera &cam); 

private: 
    ExtCamera *m_pCamera; // do not use it in inline code inside header! 
}; 

c) Un puntero puede ser eliminada en cualquier momento - por lo que tiene más control sobre el Livetime y puede volver a crear un objeto - por ejemplo en caso de un fallo.

+2

Para la inicialización lenta, recomendaría usar 'boost :: optional' siempre que sea posible. Es más seguro que el puntero porque no puede hacer aritmética en él. –

+1

Pero muchos (como yo) no usan Boost, así que esta es una plataforma y un marco de manera independiente ;-) ... Por ejemplo, solo uso Qt :-) – 3DH

+1

Pero aquellos que no usan 'boost' deberían :) – GManNickG

10

Si es posible, colóquelo en la pila, si lo necesita, en la tienda libre. Hay un similar question aquí, donde encontrará todos los "por qué". El motivo por el que se ve mucho uso del puntero cuando se trata de juegos y cosas así es porque DirectX es una interfaz COM, y honestamente, la mayoría de los programadores de juegos de la época no son realmente programadores en C++, sino que son C- los programadores con clases, y en el uso del puntero C es muy común.

17

Las ventajas de usar un puntero las describe 3DH: inicialización diferida, reducción en las dependencias del encabezado y control sobre la duración del objeto.

También son desventajas. Cuando tiene un miembro de datos de puntero, probablemente tenga que escribir su propio constructor de copia y operador de asignación, para asegurarse de que se crea una copia del objeto correctamente. Por supuesto, también debe recordar eliminar el objeto en el destructor. Además, si agrega un miembro de datos de puntero a una clase existente, debe recordar actualizar el constructor de copia y el operador =. En resumen, tener un miembro de datos de puntero es más trabajo para usted.

Otra desventaja es realmente la otra cara del control sobre la vida útil del objeto apuntado por el puntero. Los miembros de datos sin puntero se destruyen automágicamente cuando se destruye el objeto, lo que significa que siempre puede estar seguro de que existen mientras exista el objeto. Con el puntero, debe verificar que sea nullptr, lo que significa que debe asegurarse de establecerlo en nullptr siempre que no señale nada. Tener que lidiar con todo esto puede conducir fácilmente a errores.

Finalmente, es probable que el acceso a miembros que no sean punteros sea más rápido, ya que son contiguos en la memoria. Por otro lado, es probable que el acceso al miembro de datos del puntero que apunta a un objeto asignado en el montón haga que falte el caché, lo que lo hace más lento.

No hay una sola respuesta a su pregunta. Debe observar su diseño y decidir si las ventajas de los datos de los punteros superan el dolor de cabeza adicional. Si es importante reducir el tiempo de compilación y las dependencias del encabezado, use pimpl idiom. Si su miembro de datos puede no ser necesario para su objeto en ciertos casos, use un puntero y asigne cuando sea necesario. Si estos no suenan como razones convincentes, y no quiere hacer un trabajo extra, entonces no use un puntero.

3

Otra razón para usar punteros sería la vinculación dinámica. Si tiene una clase base con un método virtual y algunas clases derivadas, solo puede obtener enlaces dinámicos usando punteros.

+2

Eso no es del todo correcto: puede tener un enlace dinámico con referencias. – boxofrats

+1

Muy cierto, gracias por la aclaración. –

Cuestiones relacionadas