2010-01-17 28 views
13

Estoy intentando crear una clase que tenga un miembro privado que sea una matriz. No sé el tamaño de la matriz y no lo haré hasta que el valor pase al constructor. ¿Cuál es la mejor manera de definir el constructor de clase así como la definición en el archivo .h para permitir este tamaño variable de la matriz?Matriz como miembro privado de la clase

Respuesta

10

Si desea una matriz de estilo C "real", debe agregar un miembro privado de puntero a su clase y asignar dinámicamente la memoria para ello en el constructor (con new). Obviamente, no debes olvidar liberarlo en el destructor.

class YourClass 
{ 
    private: 
    int * array; 
    size_t size; 

    // Private copy constructor operator to block copying of the object, see later 
    // C++03: 
    YourClass(const YourClass &); // no definition 
    // C++11: 
    YourClass(const YourClass&) = delete; 

    public: 
    YourClass(size_t Size) : array(new int[Size]), size(Size) 
    { 
     // do extra init stuff here 
    }; 

    ~YourClass() 
    { 
     delete [] array; 
    } 
}; 

para hacer este trabajo más fácil, puede considerar utilizar un puntero inteligente (por ejemplo, un boost::scoped_array en C++ 03, o simplemente std::unique_ptr en C++ 11), que puede inicializar utilizando el inicializador lista antes del constructor o simplemente en el constructor.

class YourClass 
{ 
    private: 
    boost::scoped_array<int> array; // or in C++11 std::unique_ptr<int[]> array; 
    size_t size; 
    public: 
    YourClass(size_t Size) : array(new int[Size]), size(Size) 
    { 
     // do extra init stuff here 
    } 

    // No need for a destructor, the scoped_array does the magic 
}; 

Tanto estas soluciones producen objetos noncopyable (no se especificó si tuvieran que ser copiable y su copia semántica); si la clase no tiene que ser copiada (lo que sucede la mayoría de las veces), ambas están correctas, y el compilador generará un error si intentas copiar/asignar una clase a otra, en el primer caso porque la copia predeterminada el constructor se ha sobrecargado con uno privado (o un plano eliminado en C++ 11), en el segundo caso porque boost::scoped_array y std::unique_ptr no se pueden copiar.

Si, por el contrario, desea tener objetos copiables, debe decidir si desea crear una copia que comparta la matriz (por lo tanto, solo una copia de puntero) o si desea crear una nueva matriz separada para el otro objeto.

En el primer caso, debe tener mucho cuidado antes de liberar la memoria asignada, ya que otros objetos pueden estar usándola; un contador de referencia es la solución más común. Puede recibir ayuda en esto por boost::shared_array (o std::shared_ptr en C++ 11), lo que hace que todo el seguimiento funcione automáticamente para usted.

Si, por el contrario, desea hacer una "copia profunda", tendrá que asignar la nueva memoria y copiar todos los objetos de la matriz de origen a la matriz de destino. Esto no es completamente trivial para hacer correctamente, y generalmente se realiza a través del "copy and swap idiom".

Aún así, la solución más simple es usar un std::vector como miembro privado: manejaría todas las cosas de asignación/desasignación por sí mismo, construyéndose/destruyéndose correctamente cuando se construye/destruye el objeto de su clase. Además, implementa la semántica de copia profunda de la caja. Si necesita hacer que las personas que llaman accedan al vector de solo lectura, entonces, puede escribir un getter que devuelva una referencia const_iterator o const al objeto vector.

+1

Para las matrices, asegúrese de utilizar ' scoped_array', not 'scoped_ptr'. –

+0

Corregido, gracias. Siempre obtengo el delete [] correcto, pero a veces me olvidé de las versiones de matriz de los punteros inteligentes. –

+0

El único truco es si YourClass se puede copiar, porque scoped_ * no se puede copiar en el impulso. Eso no está especificado en la pregunta de todos modos, así que +1 de todos modos. – Skurmedel

2

El uso de std :: vector es la mejor opción. Si alguna vez necesita pasarlo a una función que espera un puntero a una matriz (como la GSL a menudo lo hace), aún puede pasar &vec[0] ...

Cuestiones relacionadas