2010-02-05 16 views
126

estoy empezando a entrar en C++ y quiero recoger algunos buenos hábitos. Si acabo asignado una matriz de tipo int con el operador new, ¿cómo puedo a todos a 0 inicializar sin bucle a través de todos ellos a mí mismo? ¿Debo simplemente usar memset? ¿Hay una forma “ C++ ” para hacerlo?¿Cómo inicializar la memoria con un nuevo operador en C++?

+15

Si desea obtener un buen hábito de C++, evite el uso de matrices directamente y use el vector en su lugar. Vector inicializará todos los elementos independientemente del tipo, y luego no necesita recordar llamar al operador delete []. – brianegge

+0

@brianegge: ¿Qué ocurre si necesito pasar una matriz a una función externa de C? ¿Puedo darle el vector? – dreamlax

+11

Puede pasar '& vector [0]'. – jamesdlin

Respuesta

302

Es una característica sorprendentemente poco conocido de C++ (como lo demuestra el hecho de que nadie ha dado esto como una respuesta aún), pero en realidad tiene una sintaxis especial para default- inicializar un array (bueno, técnicamente, se llama "valor de inicialización" en la Norma):

new int[10](); 

Tenga en cuenta que debe utilizar los paréntesis vacíos - no se puede, por ejemplo, utilizar (0) o cualquier otra expresión (Por eso esto solo es útil para la iniciación predeterminada lización).

Esto se permite explícitamente por ISO C++ 03 5.3.4 [expr.new]/15, que dice:

Una nueva expresión que crea un objeto de tipo T inicializa ese objeto como sigue :

...

  • Si el nuevo inicializador es de la forma(), el elemento tiene un valor inicializado (8.5);

y no restringir los tipos para los que se permite este, mientras que la forma (expression-list) se limita explícitamente por otras normas en la misma sección tal que no permite tipos de matriz.

+1

Aunque estoy de acuerdo en que esto es poco conocido, no puedo (totalmente) aceptar que sea realmente muy sorprendente: se agregó en C++ 03, que la mayoría de la gente parece haber ignorado (ya que esta era una de las pocas nuevas cosas que sí agregó). –

+1

@Jerry: Debo admitir que aún no sabía (probablemente porque cuando llegué a leer el estándar, ya era C++ 03). Dicho esto, es notable que todas las implementaciones que conozco admiten esto (creo que es porque es tan trivial de implementar). –

+1

Sí, es bastante trivial de implementar. En cuanto a ser nuevo, * all * "initialization value" era nuevo en C++ 03. –

6

Si se encuentra:

std::vector<int> vec(SIZE, 0); 

usar un vector en lugar de una matriz asignada dinámicamente. Los beneficios incluyen no tener que preocuparse por eliminar explícitamente la matriz (se elimina cuando el vector sale del alcance) y también que la memoria se elimina automáticamente incluso si se produce una excepción.

Editar: Para evitar volcadas posteriores de personas que no se molestan en leer los comentarios a continuación, debo aclarar que esta respuesta no dice que el vector es siempre la respuesta correcta. Pero seguro que es una forma más C++ que "manual", asegurándose de eliminar una matriz.

Ahora con C++ 11, también hay std :: array que los modelos de una matriz de tamaño constante (vs vector que es capaz de crecer). También hay std :: unique_ptr que gestiona una matriz asignada dinámicamente (que se puede combinar con la inicialización como se responde en otras respuestas a esta pregunta). Cualquiera de ellos es una forma más C++ que el manejo manual del puntero a la matriz, en mi humilde opinión.

+10

esto realmente no responde la pregunta que se hizo. –

+1

¿Debo usar siempre 'std :: vector' en lugar de matrices dinámicamente asignadas? ¿Cuáles son los beneficios de usar una matriz sobre un vector, y viceversa? – dreamlax

+0

Debería haber mencionado en mi pregunta, que la matriz debe persistir después del alcance actual. ¿Tengo que usar 'new std :: vector'? – dreamlax

23

Suponiendo que realmente desea una matriz y no un std :: vector, el "camino C++" sería este

#include <algorithm> 

int* array = new int[n]; // Assuming "n" is a pre-existing variable 

std::fill_n(array, n, 0); 

Pero tenga en cuenta que bajo el capó esto sigue siendo en realidad un bucle que se asigna cada elemento a 0 (realmente no hay otra manera de hacerlo, salvo una arquitectura especial con soporte de nivel de hardware).

+0

No me importa si el ciclo se implementa debajo de una función, solo quería saber si tenía que implementar ese ciclo yo mismo. Gracias por el consejo. – dreamlax

+3

Puede que se sorprenda. Yo era. En mi STL (tanto GCC como Dinkumware), std :: copy en realidad se convierte en memcpy si detecta que se está llamando con tipos incorporados. No me sorprendería si std :: fill_n utilizara memset. –

+2

No. Use 'Value-Initialization' para configurar todos los miembros a 0. –

2

std::fill es una forma. Toma dos iteradores y un valor para llenar la región. Eso, o el bucle for, sería (supongo) la forma más C++.

Para establecer una matriz de tipos enteros primitivos en 0 específicamente, memset está bien, aunque puede levantar las cejas. Considere también calloc, aunque es un poco incómodo de usar de C++ debido al lanzamiento.

Por mi parte, casi siempre uso un bucle.

(que no me gusta de adivinar las intenciones de las personas, pero es cierto que std::vector es, a igualdad de todas las cosas, preferible al uso de new[].)

0

Típicamente para las listas dinámicas de objetos, se utiliza una std::vector.

Generalmente utilizo memset o un bucle para la asignación dinámica de memoria sin formato, según la variable que anticipe que ese área de código tenga en el futuro.

7

Si la memoria que está asignando es una clase con un constructor que hace algo útil, el operador nuevo llamará a ese constructor y dejará su objeto inicializado.

Pero si asigna un POD o algo que no tiene un constructor que inicialice el estado del objeto, entonces no puede asignar memoria e inicializar esa memoria con el operador nuevo en una operación.Sin embargo, tiene varias opciones:

1) Use una variable de pila en su lugar. Puede asignar y default-initialize en un solo paso, de esta manera:

int vals[100] = {0}; // first element is a matter of style 

2) utilizan memset(). Tenga en cuenta que si el objeto que está asignando no es un POD, memsetting es una mala idea. Un ejemplo específico es que si configuras una clase que tiene funciones virtuales, eliminarás el vtable y dejarás tu objeto en un estado inutilizable.

3) Muchos sistemas operativos tienen llamadas que hacen lo que usted desea: asignar en un montón e inicializar los datos a algo. Un ejemplo de Windows sería VirtualAlloc()

4) Esta suele ser la mejor opción. Evite tener que administrar la memoria usted mismo en absoluto. Puede utilizar contenedores STL para hacer casi cualquier cosa que ver con la memoria crudo, incluyendo la asignación e inicialización de todos de una sola vez:

std::vector<int> myInts(100, 0); // creates a vector of 100 ints, all set to zero 
1

siempre se puede utilizar memset:

int myArray[10]; 
memset(myArray, 0, 10 * sizeof(int)); 
+0

Entiendo que puedo usar 'memset', pero no estaba seguro de si esta era la forma C++ de abordar el problema. – dreamlax

+0

Sí, memset funciona igual de bien en C++ que en C para configurar la memoria lineal en un valor. –

+1

No es realmente el "camino de C++", pero tampoco lo son las matrices en bruto. –

17

No es el número de métodos para asignar una matriz de tipo intrínseco y todos estos métodos son correctos, aunque cuál elegir, depende ...

Manual de inicialización de todos los elementos de bucle

int* p = new int[10]; 
for (int i = 0; i < 10; i++) 
{ 
    p[i] = 0; 
} 

Usando std::memset función de <cstring>

int* p = new int[10]; 
std::memset(p, 0, 10); 

Uso de std::fill_n algoritmo de <algorithm>

int* p = new int[10]; 
std::fill_n(p, 10, 0); 

Usando std::vector recipiente

std::vector<int> v(10); // elements zero'ed 

Si C++0x disponibles, utilizando initializer list características

int a[] = { 1, 2, 3 }; // 3-element static size array 
vector<int> v = { 1, 2, 3 }; // 3-element array but vector is resizeable in runtime 
+0

debería ser el vector Si agregó p = new int [10]() tenía una lista completa. – karsten

+0

@karsten Reparado, salud. – mloskot

Cuestiones relacionadas