Comment initialiser la mémoire avec un nouvel opérateur en C ++?

Je commence juste à me mettre au C ++ et je veux prendre de bonnes habitudes. Si je viens d’allouer un tableau de type int au new opérateur, comment puis-je les initialiser tous à 0 sans les parcourir tous moi-même? Dois-je simplement utiliser memset ? Existe-t-il un moyen «C ++» de le faire?

C’est une fonctionnalité étonnamment peu connue de C ++ (comme en témoigne le fait que personne n’a encore donné cette réponse), mais elle possède une syntaxe spéciale pour l’initialisation par défaut d’un tableau (bien, techniquement, elle s’appelle “value- initialiser “dans la norme):

 new int[10](); 

Notez que vous devez utiliser les parenthèses vides – vous ne pouvez pas, par exemple, utiliser (0) ou toute autre expression (c’est pourquoi cela n’est utile que pour l’initialisation par défaut).

Ceci est explicitement autorisé par ISO C ++ 03 5.3.4 [expr.new] / 15, qui dit:

Une nouvelle expression qui crée un object de type T initialise cet object comme suit:

  • Si le nouvel initialiseur est de la forme (), l’élément est initialisé en valeur (8.5);

et ne restreint pas les types pour lesquels cela est autorisé, tandis que la forme (expression-list) est explicitement restreinte par d’autres règles dans la même section, de sorte qu’elle n’autorise pas les types de tableau.

En supposant que vous voulez vraiment un tableau et non un std :: vector, le “moyen C ++” serait ceci

 #include  int* array = new int[n]; // Assuming "n" is a pre-existing variable std::fill_n(array, n, 0); 

Mais sachez que sous le capot, il ne s’agit en fait que d’une boucle qui assigne chaque élément à 0 (il n’y a vraiment pas d’autre moyen de le faire, sauf une architecture spéciale avec un support matériel).

Il y a un certain nombre de méthodes pour allouer un tableau de type insortingnsèque et toutes ces méthodes sont correctes, bien que laquelle choisir, dépend …

Initialisation manuelle de tous les éléments en boucle

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

Utiliser la fonction std::memset de

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

Utiliser l'algorithme std::fill_n de

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

Utilisation du std::vector

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

Si C ++ 0x est disponible, utilisez les fonctionnalités de la liste d'initialisation

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

Si la mémoire que vous allouez est une classe avec un constructeur qui fait quelque chose d’utile, l’opérateur new appelle ce constructeur et laisse votre object initialisé.

Mais si vous allouez un POD ou quelque chose qui n’a pas de constructeur qui initialise l’état de l’object, vous ne pouvez pas allouer de mémoire et initialiser cette mémoire avec un opérateur nouveau en une seule opération. Cependant, vous avez plusieurs options:

1) Utilisez plutôt une variable de stack. Vous pouvez allouer et initialiser par défaut en une seule étape, comme ceci:

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

2) utiliser memset() . Notez que si l’object que vous allouez n’est pas un POD , c’est une mauvaise idée. Un exemple spécifique est que si vous définissez une classe avec des fonctions virtuelles, vous videra la vtable et laisserez votre object dans un état inutilisable.

3) De nombreux systèmes d’exploitation ont des appels qui font ce que vous voulez – allouer sur un tas et initialiser les données à quelque chose. Un exemple Windows serait VirtualAlloc()

4) C’est généralement la meilleure option. Évitez de gérer vous-même la mémoire. Vous pouvez utiliser des conteneurs STL pour faire à peu près tout ce que vous feriez avec la mémoire brute, y compris l’allocation et l’initialisation d’un seul coup:

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

Oui il y a:

 std::vector vec(SIZE, 0); 

Utilisez un vecteur au lieu d’un tableau alloué dynamicment. Les avantages comprennent le fait de ne pas avoir à supprimer explicitement le tableau (il est supprimé lorsque le vecteur est hors de scope) et que la mémoire est automatiquement supprimée même si une exception est levée.

Edit: Pour éviter que d’autres personnes qui ne lisent pas les commentaires ci-dessous ne soient incités à conduire, je devrais préciser que cette réponse ne dit pas que le vecteur est toujours la bonne réponse. Mais c’est sûrement un moyen plus C ++ que de “supprimer” manuellement un tableau.

Maintenant, avec C ++ 11, il y a aussi std :: array qui modélise un tableau de taille constante (vs vecteur capable de croître). Il y a aussi std :: unique_ptr qui gère un tableau alloué dynamicment (qui peut être combiné avec une initialisation répondant à d’autres réponses à cette question). N’importe lequel d’entre eux est un moyen plus C ++ que de gérer manuellement le pointeur vers le tableau, à mon humble avis.

std::fill est un moyen. Prend deux iterators et une valeur pour remplir la région. Cela, ou la boucle for, serait (je suppose) la plus C ++.

Pour définir un tableau de types entiers primitifs à 0 spécifiquement, memset est memset , bien qu’il puisse susciter des sourcils. Considérez aussi calloc , même si c’est un peu gênant d’utiliser C ++ à cause de la dissortingbution.

Pour ma part, j’utilise presque toujours une boucle.

(Je n’aime pas deviner les intentions des gens, mais il est vrai que std::vector est, toutes choses égales par ailleurs, préférable à new[] .)

vous pouvez toujours utiliser memset:

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

Généralement, pour les listes dynamics d’éléments, vous utilisez un std::vector .

En général, j’utilise memset ou une boucle pour une allocation dynamic de mémoire brute, en fonction de la variable que j’anticipe dans le futur.