2010-01-09 8 views
17

Me gustaría utilizar boost :: array como miembro de la clase, pero no sé el tamaño en el momento de la compilación. pensé en algo así, pero no funciona:Cómo usar boost :: array con un tamaño desconocido como variable de objeto

int main() { 
    boost::array<int, 4> array = {{1,2,3,4}}; 
    MyClass obj(array); 
} 

class MyClass { 
    private: 
     boost::array<int, std::size_t> array; 
    public: 
     template<std::size_t N> MyClass(boost::array<int, N> array) 
     : array(array) {}; 
}; 

El compilador gcc, dice:

error: type/value mismatch at argument 2 in template parameter list for 
    ‘template<class _Tp, long unsigned int _Nm> struct boost::array’ 
error: expected a constant of type ‘long unsigned int’, got ‘size_t’ 

Lo que obviamente significa que no se puede utilizar matrices de tamaño variable como miembros de la clase . Si es así, esto anularía todas las ventajas de boost :: array sobre vectores o arreglos estándar.

¿Me puede mostrar lo que hice mal?

Respuesta

19

de Boost es de tamaño fijo basado en el segundo parámetro de plantilla, y boost::array<int,4> es un diferente tipo de boost::array<int,2>. No puede tener instancias de la misma clase (MyClass en su ejemplo) que tienen diferentes tipos para sus miembros.

Sin embargo, std :: vectores pueden tener diferentes tamaños sin ser de diferentes tipos:

struct MyClass { 
    template<std::size_t N> 
    explicit 
    MyClass(boost::array<int, N> const& array) 
    : data(array.begin(), array.end()) 
    {} 

private: 
    std::vector<int> data; 
}; 

int main() { 
    boost::array<int, 4> a = {{1,2,3,4}}; 
    MyClass obj(a); 

    boost::array<int, 2> a2 = {{42,3}}; 
    MyClass obj2(a2); 

    // notice obj.data.size() != obj2.data.size() 

    return 0; 
} 

Dicho esto, boost :: array es todavía útil (es incluso más útil en este código de ejemplo), pero no en el forma exacta en que quieres usarlo

1

estás equivocado acerca del error:

template<unsigned long N> MyClass(boost::array<int, N> array) : array(array) {}; 

debería funcionar. Por cierto, esto todavía generará la matriz en tiempo de compilación, por lo que no es una buena solución. Y otros errores ocurrirán.

Aquí lo que quiere es un vector, con un tamaño reservado y algunas aserciones que mantienen la capacidad en un tamaño fijo.

+0

El error mencionado es sobre 'boost :: array ', y él parece interpretarlo correctamente –

3

No, boost :: array (está en TR1 como std :: tr1 :: array) es un buffer de tamaño estático. El objetivo de la clase es evitar una asignación de memoria dinámica: puede colocar una matriz boost :: completamente en la pila.

Usted puede hacer que su clase de ejemplo tomar un int plantilla y pasar que al impulso miembro de la matriz ::,

template<int Size> 
class MyClass 
{ 
private: 
    boost::array<int, Size> m_array; 
public: 
    // .... 
}; 

pero eso es sólo vestirse, sigue siendo una asignación estática. array

+0

Tenga en cuenta que esta solución traslada el problema a la clase MyClass (donde cada creación de instancia de plantilla se convertirá en un tipo diferente). Dependiendo de la tarea real del interrogador esto puede funcionar, pero lo dudo. – Frunsi

+0

También "no es" asignación, la frase es engañosa. – Frunsi

+0

Eso es lo que quise decir con solo "vestirse", y las asignaciones de tamaño estático (y las asignaciones de pila) siguen siendo asignaciones. –

5

¿Puedo sugerir usar boost::scoped_array en su lugar? Por otro lado, es posible que no desee realmente copiar toda la matriz cada vez. Entonces boost::shared_array sería una mejor opción.

1

Aunque ya haya aceptado una respuesta, tenga en cuenta que std :: vector puede no sea la elección correcta para su tarea. Si desea crear la matriz una vez - una matriz de tamaño fijo - y no desea volver a clasificar según el tamaño más adelante, entonces una buena y vieja matriz puede ser la elección correcta para usted! Ignore boost :: array, ignore std :: vector, sus intenciones son muy diferentes, manténgala simple. KISS, YAGNI y así sucesivamente ...

int main() { 
    int* array = new int[4]; 
    for(int i=0; i<4; ++i) array[i] = i+1; 
    MyClass obj(array); 
} 

class MyClass { 
    private: 
     int* array; 
    public: 
     MyClass(int* array) 
     : array(array) {} 
     ~MyClass() { delete[] array; } 
}; 

EDIT: Como Nikolai N Fetissov ya se ha dicho, impulsar :: scoped_array podría ser una buena opción. Proporciona un envoltorio RAII fino alrededor de la matriz. Aquí es un ejemplo de uso (espero que sea correcta, no dude en editar lo contrario):

class MyClass { 
    private: 
     boost::scoped_array<int> array; 
    public: 
     MyClass(int* array) 
     : array(array) {} 
}; 
+0

Hmm, aquí falta el constructor de copia y el operador de asignación de copia. –

+1

boost :: array/tr1 :: array es un contenedor muy fino alrededor de una matriz de tamaño fijo; de hecho, tiene cero sobrecarga. Literalmente, no hay ninguna razón para usar una matriz estilo C cuando tr1 :: array está disponible. –

+1

Terry: ¿has leído la pregunta real? No hay razón para rechazarme, si no entendiste la intención del interrogador. – Frunsi

12

que faltan algunos puntos básicos. Puede tener:

  1. Un estáticamente asignado serie - char arr[10];
  2. Un dinámicamente asignado serie - char* arr = new arr[10];

tamaño El primero de uno es conocido en tiempo de compilación (porque el tamaño es una constante), por lo tanto, puede preasignar un espacio de memoria para ello, el otro no, por lo que debe asignar memoria para ello durante el tiempo de ejecución.

STL/TR1/Boost proporciona envolturas para ambos tipos de matrices. Esos no son solo envoltorios por conveniencia, sino también por seguridad (control de rango en algunas situaciones) y potencia (iteradores). Para ambos casos tenemos un envoltorio separado:

  1. estáticamente asignada array envoltura boost::array<char,10> arr;
  2. dinámicamente asignada envoltura array std::vector<char> arr;

Este último tiene la ventaja de ser auto cambio de tamaño, y permitiendo el cambio de tamaño, además a ser dinámicamente asignables. boost::array por otro lado, imita una construcción type arr[const].

Por lo tanto, debe decidir si desea que la clase tenga memoria estáticamente asignada, o dinámicamente. Lo primero, solo tiene sentido si el almacenamiento de las clases es de tamaño fijo o uno de los pocos tamaños fijos. Esto último tiene sentido en todos los demás casos.

reserva estáticamente sería utilizar plantillas

template < size_t N > 
class MyClass { 
private: 
    boost::array< int, N > array; 
public: 
    MyClass(boost::array< int, N > array) : array(array) {}; 
}; 

// ... 

boost::array<int, 4> array = {{1,2,3,4}}; 
MyClass<4> obj(array); 

Pero crearía código separado para cada tamaño de la clase, y no serían interoperables (esto se puede evitar sin embargo).

asignados dinámicamente utilizaría vectores

class MyClass { 
private: 
    std::vector<int> array; 
public: 
    MyClass(const std::vector<int>& array) : array(array) {}; 
}; 

No tenga miedo de vectores, los tratan como matrices asignados dinámicamente - la resizingness de vectores es un beneficio adicional que no afecta al rendimiento casi al todas.

0

Si usted no necesita cambio de tamaño dinámico, no es necesario std :: vector

solo tienen la función de aceptar * int

MyFunction (int* array,int size); // function prototype 

y pasarlo al impulso :: array 's .data() apunta a los datos ...

boost::array<int,4> testArray; 
boost::array<int,5> testArray2; 

// Calling the function: 
MyFunction(testArray.data(),4); 
MyFunction(testArray2.data(),5); 

la clave es .data() gente !!! Si desea aumentar matrices para reemplazar matrices regulares, esta es quizás la forma (sin tener que usar plantillas y todo eso)

Cuestiones relacionadas