Je suis tombé sur un quiz impliquant une déclaration de tableau de différentes tailles. La première chose qui m'est venue à l'esprit est que je devrais utiliser l'allocation dynamique avec la new
commande, comme ceci:
while(T--) {
int N;
cin >> N;
int *array = new int[N];
// Do something with 'array'
delete[] array;
}
Cependant, j'ai vu que l'une des solutions permettait le cas suivant:
while(T--) {
int N;
cin >> N;
int array[N];
// Do something with 'array'
}
Après un peu de recherche, j'ai lu que g ++ le permet, mais cela m'a fait réfléchir, dans quels cas est-il alors nécessaire d'utiliser l'allocation dynamique? Ou est-ce que le compilateur traduit cela comme une allocation dynamique?
La fonction de suppression est incluse. Notez cependant que la question ici ne concerne pas les fuites de mémoire.
c++
arrays
dynamic-memory-allocation
static-memory-allocation
learning_dude
la source
la source
std::vector
plutôt (std::vector<int> array(N);
).new OBJ
directement.Réponses:
Aucun extrait que vous montrez n'est un code C ++ moderne idiomatique.
new
etdelete
(etnew[]
etdelete[]
) ne sont pas obsolètes en C ++ et ne le seront jamais. Ils sont toujours le moyen d'instancier des objets alloués dynamiquement. Cependant, comme vous devez toujours faire correspondre unnew
avec undelete
(et unnew[]
avec undelete[]
), il est préférable de les conserver dans des classes (bibliothèque) qui vous garantissent cela. Voir Pourquoi les programmeurs C ++ devraient-ils minimiser l'utilisation de «nouveau»? .Votre premier extrait de code utilise un "nu"
new[]
et puis jamaisdelete[]
le tableau créé. C'est un problème.std::vector
fait tout ce dont vous avez besoin ici très bien. Il utilisera une certaine forme denew
coulisses (je ne plongerai pas dans les détails d'implémentation), mais pour tout ce que vous avez à faire, c'est un tableau dynamique mais meilleur et plus sûr.Votre deuxième extrait utilise des "tableaux de longueur variable" (VLA), une fonctionnalité C que certains compilateurs autorisent également en C ++ comme extension. Contrairement aux
new
VLA, ils sont essentiellement alloués sur la pile (une ressource très limitée). Mais plus important encore, ils ne sont pas une fonctionnalité C ++ standard et doivent être évités car ils ne sont pas portables. Ils ne remplacent certainement pas l'allocation dynamique (c'est-à-dire le tas).la source
Qt
, car ses classes de base ont toutes des ramasse-miettes, vous devez donc simplement l'utilisernew
et l'oublier, la plupart du temps. Pour les éléments de l'interface graphique, lorsque le widget parent est fermé, les enfants sortent de la portée et sont automatiquement récupérés.new
toujours une correspondancedelete
; c'est juste que lesdelete
s sont effectués par le widget parent plutôt que dans le même bloc de code que lesnew
s.Eh bien, pour commencer,
new
/delete
ne sont pas obsolètes.Dans votre cas particulier, ce n'est pas la seule solution. Ce que vous choisissez dépend de ce qui a été caché sous votre commentaire "faire quelque chose avec le tableau".
Votre 2ème exemple utilise une extension VLA non standard qui essaie d'adapter le tableau sur la pile. Cela a certaines limites - à savoir une taille limitée et l'impossibilité d'utiliser cette mémoire après que le tableau soit hors de portée. Vous ne pouvez pas le déplacer, il "disparaîtra" après le déroulement de la pile.
Donc, si votre seul objectif est de faire un calcul local, puis de jeter les données, cela pourrait fonctionner correctement. Cependant, une approche plus robuste consisterait à allouer la mémoire dynamiquement, de préférence avec
std::vector
. De cette façon, vous avez la possibilité de créer de l'espace pour exactement autant d'éléments que vous en avez besoin en vous basant sur une valeur d'exécution (ce que nous recherchons tout au long), mais cela se nettoiera également bien et vous pourrez le déplacer de cette portée si vous souhaitez conserver la mémoire en cours d'utilisation pour plus tard.En revenant au début, vous
vector
utiliserez probablementnew
quelques couches plus en profondeur, mais vous ne devriez pas vous en préoccuper, car l'interface qu'elle présente est bien supérieure. En ce sens, l'utilisationnew
etdelete
peut être considérée comme découragée.la source
new
etdelete
, mais plutôt utiliser des pointeurs intelligents commestd::unique_pointer
.std::unique_ptr
std::unique_ptr
le destructeur par défaut appelledelete
oudelete[]
, ce qui signifie que l'objet possédé doit avoir été alloué parnew
ou denew[]
toute façon, dans quels appels sont cachésstd::make_unique
depuis C ++ 14.Vos deuxièmes exemples utilisent des tableaux de longueur variable (VLA), qui sont en fait une fonctionnalité C99 ( pas C ++!), Mais néanmoins pris en charge par g ++ .
Voir aussi cette réponse .
Notez que les tableaux de longueur variable sont différents de
new
/delete
et ne les "déconseillent" en aucune façon.Sachez également que les VLA ne sont pas ISO C ++.
la source
Le C ++ moderne offre des moyens plus simples de travailler avec des allocations dynamiques. Les pointeurs intelligents peuvent prendre soin du nettoyage après les exceptions (qui peuvent se produire n'importe où si autorisé) et les retours précoces, dès que les structures de données référencées sortent du domaine, il peut donc être judicieux de les utiliser à la place:
A partir de C ++ 14, vous pouvez également écrire
cela semble encore plus agréable et empêcherait une fuite de mémoire en cas d'échec de l'allocation. A partir de C ++ 20, vous devriez pouvoir faire autant que
pour moi, cela ne se compile toujours pas au moment de l'écriture avec gcc 7.4.0. Dans ces deux exemples, nous utilisons également la
auto
déclaration de type à gauche. Dans tous les cas, utilisez le tableau comme d'habitude:Les fuites de mémoire
new
et les plantages de doublésdelete
sont quelque chose que le C ++ a été critiqué pendant de nombreuses années, étant le "point central" de l'argumentation pour passer à d'autres langages. Peut-être préférable d'éviter.la source
unique/shared_ptr
constructeurs en faveur demake_unique/shared
, non seulement vous n'avez pas à écrire deux fois le type construit (en utilisantauto
), mais vous ne risquez pas de fuir la mémoire ou les ressources si la construction échoue à mi-chemin (si vous utilisez un type qui peut échouer)make_shared<int[]>
grand-chose, quand vous en avez presque toujours envievector<int>
, mais bon à savoir.unique_ptr
constructeur n'est pas jeter, donc pour ceuxT
qui n'ont pas de constructeurs, il n'y a donc aucun risque de fuite avecunique_ptr(new int[size])
etshared_ptr
a ce qui suit: "Si une exception est levée, supprimer p est appelé lorsque T n'est pas un type de tableau, supprimer [ ] p sinon. ", vous avez donc le même effet - le risque est pourunique/shared_ptr(new MyPossiblyAllocatingType[size])
.new et delete ne sont pas obsolètes.
Les objets créés par le nouvel opérateur peuvent être passés par référence. Les objets peuvent être supprimés à l'aide de la suppression.
nouveau et supprimer sont les aspects fondamentaux de la langue. La persistance d'un objet peut être gérée en utilisant new et delete. Ceux-ci ne seront certainement pas dépréciés.
L'instruction - int array [N] est un moyen de définir un tableau. Le tableau peut être utilisé dans le cadre du bloc de code englobant. Il ne peut pas être transmis comme la façon dont un objet est passé à une autre fonction.
la source
Le premier exemple a besoin d'un
delete[]
à la fin, ou vous aurez une fuite de mémoire.Le deuxième exemple utilise une longueur de tableau variable qui n'est pas prise en charge par C ++; il autorise uniquement l'expression constante pour la longueur du tableau .
Dans ce cas, il est utile d'utiliser
std::vector<>
comme solution; qui encapsule toutes les actions que vous pouvez effectuer sur un tableau dans une classe de modèle.la source
La syntaxe ressemble à C ++, mais l'idiome est similaire à l'ancien Algol60 simple. Il était courant d'avoir des blocs de code comme celui-ci:
L'exemple pourrait s'écrire:
Cela me manque parfois dans les langues actuelles;)
la source