c++ - memoria - punteros a cadenas
¿Cómo inicializar la memoria con un nuevo operador en C++? (8)
Estoy empezando a entrar en C ++ y quiero aprender buenos hábitos. Si acabo de asignar una matriz de tipo int
con el new
operador, ¿cómo puedo inicializarlos todos en 0 sin pasarlos por todos? ¿Debería usar memset
? ¿Hay alguna forma de "C ++" para hacerlo?
Asumiendo que realmente quieres una matriz y no un std :: vector, la "forma C ++" sería esta
#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 todavía es realmente un ciclo que asigna cada elemento a 0 (realmente no hay otra manera de hacerlo, salvo una arquitectura especial con soporte de nivel de hardware).
Es una característica sorprendentemente poco conocida de C ++ (como lo demuestra el hecho de que nadie ha dado esto como respuesta aún), pero en realidad tiene una sintaxis especial para inicializar por defecto una matriz (bueno, técnicamente, se llama "valor- inicializar "en el estándar):
new int[10]();
Tenga en cuenta que debe usar los paréntesis vacíos: no puede, por ejemplo, usar (0)
o cualquier otra expresión (por lo que esto solo es útil para la inicialización predeterminada).
Esto está explícitamente permitido 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 de la siguiente manera:
...
- Si el nuevo inicializador es de la forma (), el elemento se inicializa en valor (8.5);
y no restringe los tipos para los que esto está permitido, mientras que el formulario (expression-list)
está explícitamente restringido por otras reglas en la misma sección, de modo que no permite tipos de matriz.
Hay una cantidad de métodos para asignar una matriz de tipo intrínseco y todos estos métodos son correctos, aunque cuál elegir, depende ...
Inicialización manual de todos los elementos en bucle
int* p = new int[10];
for (int i = 0; i < 10; i++)
{
p[i] = 0;
}
Usar la función std::memset
de <cstring>
int* p = new int[10];
std::memset(p, 0, 10);
Usando el algoritmo std::fill_n
de <algorithm>
int* p = new int[10];
std::fill_n(p, 10, 0);
Usando std::vector
contenedor de std::vector
std::vector<int> v(10); // elements zero''ed
Si C++0x disponible, usa las funciones de la lista de inicialización
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
Normalmente, para listas dinámicas de artículos, usted usa un std::vector
.
En general, utilizo memset o un bucle para la asignación dinámica de la memoria bruta, según la variable que anticipe que ese área de código tenga en el futuro.
Sí hay:
std::vector<int> vec(SIZE, 0);
Use un vector en lugar de una matriz dinámicamente asignada. 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 nuevos votos negativos de personas que no se molestan en leer los comentarios a continuación, debo aclarar que esta respuesta no dice que el vector siempre sea 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 modela una matriz de tamaño constante (frente a un vector que puede 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.
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 está asignando 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, tienes varias opciones:
1) Use una variable de pila en su lugar. Puede asignar e default-initialize en un paso, como este:
int vals[100] = {0}; // first element is a matter of style
2) usar 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 usar contenedores STL para hacer casi cualquier cosa que haría con la memoria sin procesar, incluida la asignación e inicialización de una sola vez:
std::vector<int> myInts(100, 0); // creates a vector of 100 ints, all set to zero
siempre puedes usar memset:
int myArray[10];
memset( myArray, 0, 10 * sizeof( int ));
std::fill
es de una sola manera. 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 configurar una matriz de tipos enteros primitivos a 0 específicamente, memset
está bien, aunque puede levantar las cejas. Considere también el uso de calloc
, aunque es un poco incómodo usar C ++ debido al lanzamiento.
Por mi parte, casi siempre uso un bucle.
(No me gusta cuestionar las intenciones de las personas, pero es cierto que std::vector
es, en igualdad de condiciones, preferible al uso de new[]
).