Inicializar una matriz de miembros en el inicializador del constructor

98
class C 
{
public:
 C() : arr({1,2,3}) //doesn't compile
{}
    /*
    C() : arr{1,2,3} //doesn't compile either
{}
    */
private:
 int arr[3];
};

Creo que la razón es que las matrices solo se pueden inicializar con =sintaxis, es decir:

int arr[3] = {1,3,4};

Preguntas

  1. ¿Cómo puedo hacer lo que quiero hacer (es decir, inicializar una matriz en un constructor (sin asignar elementos en el cuerpo)). ¿Es siquiera posible?
  2. ¿El estándar C ++ 03 dice algo especial sobre la inicialización de agregados (incluidas las matrices) en los inicializadores de ctor? ¿O la invalidez del código anterior es un corolario de algunas otras reglas?
  3. ¿Las listas de inicializadores C ++ 0x resuelven el problema?

PD: Por favor, no menciones los vectores, boost :: arrays y su superioridad a los arrays, que yo conozco bien.

Armen Tsirunyan
fuente
¿Conoce también la existencia de matrices de tamaño fijo boost, que proporcionan constructores?
Benoît
2
@ Benoît: Lo soy. Pero necesito saber acerca de las matrices simples :)
Armen Tsirunyan

Respuestas:

55
  1. ¿Cómo puedo hacer lo que quiero hacer (es decir, inicializar una matriz en un constructor (sin asignar elementos en el cuerpo)). ¿Es siquiera posible?

Si. Está usando una estructura que contiene una matriz. Dices que ya lo sabes, pero luego no entiendo la pregunta. De esta manera, se hace inicializar una matriz en el constructor, sin asignaciones en el cuerpo. Esto es lo que boost::arrayhace.

¿El estándar C ++ 03 dice algo especial sobre la inicialización de agregados (incluidas las matrices) en los inicializadores de ctor? ¿O la invalidez del código anterior es un corolario de algunas otras reglas?

Un mem-initializer usa inicialización directa. Y las reglas de la cláusula 8 prohíben este tipo de cosas. No estoy exactamente seguro sobre el siguiente caso, pero algunos compiladores lo permiten.

struct A {
  char foo[6];
  A():foo("hello") { } /* valid? */
};

Consulte este PR de GCC para obtener más detalles.

¿Las listas de inicializadores C ++ 0x resuelven el problema?

Ellos si. Sin embargo, creo que su sintaxis no es válida. Tienes que usar llaves directamente para disparar la inicialización de la lista

struct A {
  int foo[3];
  A():foo{1, 2, 3} { }
  A():foo({1, 2, 3}) { } /* invalid */
};
Johannes Schaub - litb
fuente
Me encontré con esto cuando escribí: char * const foo[6];miembro de la clase. Se requiere el inicializador para compilar en C ++ 11.
JATothrim
33

C ++ 98 no proporciona una sintaxis directa para nada más que poner a cero (o para elementos que no son POD, inicializar valor) la matriz. Para eso solo escribeC(): arr() {} .

Creo que Roger Pate está equivocado acerca de las supuestas limitaciones de la inicialización agregada de C ++ 0x, pero soy demasiado vago para buscarlo o verificarlo, y no importa, ¿verdad? EDITAR : Roger estaba hablando de "C ++ 03", lo leí mal como "C ++ 0x". Lo siento, Roger. ☺

Una solución de C ++ 98 para su código actual es envolver la matriz en a structe inicializarla a partir de una constante estática de ese tipo. De todos modos, los datos deben residir en algún lugar. De improviso, puede verse así:

class C 
{
public:
    C() : arr( arrData ) {}

private:
     struct Arr{ int elem[3]; };
     Arr arr;
     static Arr const arrData;
};

C::Arr const C::arrData = {{1, 2, 3}};
Saludos y hth. - Alf
fuente
¿Qué limitaciones dije que tiene 0x?
@Roger: "inicialización agregada ... no cabe en un inicializador ctor". Simplemente verificando C ++ 0x draft N3126, la sintaxis de un inicializador de mem , en §12.5.2 / 1, incluye el uso de una lista de inicialización entre llaves .
Saludos y hth. - Alf
6
Las dos primeras palabras de mi oración están en C ++ 03, ...
8

Solución alterna:

template<class T, size_t N>
struct simple_array { // like std::array in C++0x
   T arr[N];
};


class C : private simple_array<int, 3> 
{
      static simple_array<int, 3> myarr() {
           simple_array<int, 3> arr = {1,2,3};
           return arr;
      }
public:
      C() : simple_array<int, 3>(myarr()) {}
};
Alexey Malistov
fuente
3
  1. No Desafortunadamente.
  2. Simplemente no puede de la manera que desea, ya que la gramática no lo permite (más abajo). Solo puede usar la inicialización similar a ctor y, como sabe, eso no está disponible para inicializar cada elemento en las matrices.
  3. Creo que sí, ya que generalizan la inicialización en todos los ámbitos de muchas formas útiles. Pero no estoy seguro de los detalles.

En C ++ 03, la inicialización agregada solo se aplica con una sintaxis similar a la siguiente, que debe ser una declaración separada y no cabe en un inicializador de ctor.

T var = {...};

fuente
2

Qué tal si

...
  C() : arr{ {1,2,3} }
{}
...

?

Compila bien en g ++ 4.8

viejo
fuente
¿Es este estándar? ¿Puede citar la cláusula correspondiente, por favor?
Armen Tsirunyan
2
No se compila en Visual C ++.
sergiol
-2

¿Quieres iniciar una matriz de entradas en tu constructor? Apúntelo a una matriz estática.

class C 
{
public:
    int *cArray;

};

C::C {
    static int c_init[]{1,2,3};
    cArray = c_init;
}
DaveEff
fuente
2
Esta es una mala idea, porque si cambia esa matriz, se cambia para todas las instancias de esa clase.
Morty