Nouveau (std:: nothrow) vs nouveau dans un bloc try/catch

J'ai fait quelques recherches après avoir appris new, contrairement à {[3] } auquel je suis habitué, ne retourne pas NULL pour les allocations échouées, et j'ai trouvé qu'il y avait deux façons distinctes de vérifier si new avait réussi ou non. Ces deux façons sont:

try
{
    ptr = new int[1024];
}
catch(std::bad_alloc& exc)
{
    assert();
};

Et

ptr = new (std::nothrow) int[1024];
if(ptr == NULL) 
    assert();

Je crois que les deux façons d'atteindre le même but, (corrigez-moi si je me trompe bien sûr!), donc ma question est la suivante:

Quelle est la meilleure option pour vérifier si new a réussi, basée entièrement sur la lisibilité, maintenabilité et performance, tout en ignorant la convention de programmation C++ de facto.

38
demandé sur Anne Quinn 2011-09-02 03:09:37

4 réponses

Considérez ce que vous faites. Vous êtes d'une allocation de mémoire. Et si pour une raison quelconque l'allocation de mémoire ne peut pas fonctionner, Vous assert. Ce qui est plus ou moins exactement ce qui se passera si vous laissez simplement le std::bad_alloc se propager à main. Dans une version de version, où assert est un no-op, votre programme se bloque lorsqu'il essaie d'accéder à la mémoire. C'est donc la même chose que de laisser l'exception éclater: arrêter l'application.

, Donc vous poser une question: avez-vous vraiment besoin de soins de ce qui se passe si vous exécuter de mémoire? Si tout ce que vous faites est d'affirmer, alors la méthode d'exception est meilleure, car elle n'encombre pas votre code avec des assertaléatoires. vous laissez simplement l'exception retomber sur main.

Si vous avez en fait un chemin de code spécial dans le cas où vous ne pouvez pas allouer de mémoire (c'est-à-dire que vous pouvez continuer à fonctionner), les exceptions peuvent ou non être une solution, en fonction de ce que le chemin de code est. Si le codepath est juste un commutateur défini en ayant un pointeur null, alors le nothrow version sera plus simple. Si à la place, vous devez faire quelque chose de plutôt différent (tirer d'un tampon statique, ou supprimer des choses, ou autre), alors attraper std::bad_alloc est assez bon.

48
répondu Nicol Bolas 2011-09-01 23:25:46

Cela dépend du contexte de l'endroit où l'allocation a lieu. Si votre programme peut continuer même si l'allocation échoue (peut-être renvoyer un code d'erreur à l'appelant), utilisez la méthode std::nothrow et vérifiez la valeur NULL. Sinon, vous utiliseriez des exceptions pour le flux de contrôle, ce qui n'est pas une bonne pratique.

D'autre part, si votre programme a absolument besoin d'avoir cette mémoire allouée avec succès pour pouvoir fonctionner, utilisez try-catch pour attraper (pas nécessairement dans l'immédiat proximité de la new) une exception et quitter gracieusement du programme.

10
répondu Praetorian 2011-09-01 23:21:55

Du point de vue de la performance pure, cela importe peu. Il y a des frais généraux inhérents à la gestion des exceptions, bien que ces frais généraux valent généralement le compromis en matière de lisibilité et de maintenance des applications. Les échecs d'allocation de mémoire de cette nature ne devraient pas être dans le cas de 99% de votre application, donc cela devrait se produire rarement.

Du point de vue des performances, vous voulez généralement éviter l'allocateur standard en raison de ses performances relativement faibles.

Tous cela dit, j'accepte généralement la version de lancement d'exception parce que généralement nos applications sont dans un état où si l'allocation de mémoire échoue, il y a peu que nous pouvons faire autre chose que quitter gracieusement avec un message d'erreur approprié, et nous économisons les performances en n'exigeant pas NULL vérifier nos ressources nouvellement allouées car par définition un échec

6
répondu Chad 2011-09-01 23:25:38

new est utilisé pour créer des objets, pas allouer de la mémoire, donc votre exemple est quelque peu artificiel.

Les constructeurs D'objets lancent généralement s'ils échouent. Après avoir traversé l'implémentation new Dans Visual Studio Plus de quelques fois, je ne crois pas que le code attrape des exceptions. Il est donc généralement logique de rechercher des exceptions lors de la création d'objets.

Je pense std::bad_alloc est levée uniquement si la partie d'allocation de mémoire échoue. Je ne suis pas sûr de ce que arrive si vous passez std::nothrow à new mais le constructeur d'objet jette - il y a une ambiguïté dans les documents que j'ai lus.

La différence de performance entre les 2 approches n'est probablement pas pertinente puisque la plupart du temps du processeur peut facilement être dépensé dans le constructeur d'objet ou la recherche du tas.

Une règle empirique n'est pas toujours appropriée. Par exemple, les systèmes en temps réel limitent généralement les allocations de mémoire dynamique, de sorte que new, s'il est présent, serait probablement surchargé. Dans dans ce cas, il peut utiliser un pointeur NULL retourné et gérer l'échec localement.

-3
répondu drivebycoder 2015-07-03 18:52:02