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++?
Respuesta
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.
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ó). –
@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). –
Sí, es bastante trivial de implementar. En cuanto a ser nuevo, * all * "initialization value" era nuevo en C++ 03. –
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.
esto realmente no responde la pregunta que se hizo. –
¿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
Debería haber mencionado en mi pregunta, que la matriz debe persistir después del alcance actual. ¿Tengo que usar 'new std :: vector'? – dreamlax
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).
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
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. –
No. Use 'Value-Initialization' para configurar todos los miembros a 0. –
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[]
.)
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.
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
siempre se puede utilizar memset:
int myArray[10];
memset(myArray, 0, 10 * sizeof(int));
Entiendo que puedo usar 'memset', pero no estaba seguro de si esta era la forma C++ de abordar el problema. – dreamlax
Sí, memset funciona igual de bien en C++ que en C para configurar la memoria lineal en un valor. –
No es realmente el "camino de C++", pero tampoco lo son las matrices en bruto. –
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
- 1. Uso nuevo operador para inicializar una matriz
- 2. Inicializar un objeto con y sin nuevo operador
- 3. Nuevo operador de C++ - diseño de memoria
- 4. ¿Qué usar - "operador nuevo" u "operador nuevo []" - para asignar un bloque de memoria sin procesar en C++?
- 5. Cómo inicializar un nuevo Camera.Size en Android
- 6. nuevo operador para asignación de memoria en el montón
- 7. Sobrecarga global operador nuevo/eliminar en C++
- 8. ¿Puede C++ 0x todavía asignar explícitamente con operador global nuevo?
- 9. ¿Diferencia entre 'nuevo operador' y 'operador nuevo'?
- 10. Definición de un nuevo operador de Vim con un parámetro
- 11. ¿Cómo inicializar limpiamente los atributos en Ruby con nuevo?
- 12. ¿Es posible crear un nuevo operador en C#?
- 13. el operador "nuevo" en C++, pregunta del puntero
- 14. Anulando operador global nuevo para rastrear grandes asignaciones de memoria?
- 15. Cómo burlarse del operador 'nuevo'
- 16. Cómo inicializar un semáforo binario en C
- 17. ¿Cómo inicializar un NSMutableArray en Objective C?
- 18. nuevo o nuevo código de operador []
- 19. ¿Cómo puedo crear un nuevo operador en PHP?
- 20. Cómo inicializar un struct en C#
- 21. cómo inicializar un vector en C++
- 22. ¿Cómo inicializar un puntero a una estructura en C?
- 23. operador nuevo con la opción nothrow todavía lanza excepción
- 24. asignación de memoria en C++
- 25. ¿Cómo asignar espacio de memoria sin utilizar malloc o un nuevo operador?
- 26. Cómo inicializar const en una estructura en C (con malloc)
- 27. ¿Por qué no usamos el nuevo operador al inicializar una cadena?
- 28. Operador de mezcla nuevo [] y colocación nuevo con eliminación normal []
- 29. ¿Cuál es la mejor solución para reemplazar un nuevo asignador de memoria en un código existente?
- 30. ¿Cómo llamo al "operador nuevo" original si lo sobrecargué?
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
@brianegge: ¿Qué ocurre si necesito pasar una matriz a una función externa de C? ¿Puedo darle el vector? – dreamlax
Puede pasar '& vector [0]'. – jamesdlin