12
votes

Politique avec capture STD :: Bad_alloc

J'utilise beaucoup qt avec mon développement et j'adore ça. Le modèle de conception habituel avec des objets QT est de les affecter en utilisant nouveau .

À peu près tous les exemples (en particulier le code généré par le concepteur Qt) ne vérifie absolument aucune vérification du std :: Bad_alloc Exception. Étant donné que les objets alloués (généralement des widgets et tels) sont petits, cela n'est guère jamais un problème. Après tout, si vous échouez d'allouer quelque chose comme 20 octets, les chances sont qu'il n'y a pas grand chose à faire pour remédier au problème.

Actuellement, j'ai adopté une politique d'emballage "gros" (tout ce qui est au-dessus d'une page ou d'une taille de deux personnes) dans un essai / attrape. Si cela échoue, j'affiche un message à l'utilisateur, à peu près tout petit, je vais simplement laisser l'application crash avec un std :: bad_alloc exception.

Alors, je me demande quelles sont les écoles de pensée à ce sujet?

Est-ce une bonne politique de vérifier chaque opération nouvelle ? Ou seulement ceux que je m'attends à avoir le potentiel d'échec?

En outre, il s'agit clairement d'une histoire complète lorsqu'il s'agit d'un environnement intégré dans lequel les ressources peuvent être beaucoup plus contraignantes. Je demande dans le contexte d'une application de bureau, mais serait intéressé par les réponses impliquant d'autres scénarios.


0 commentaires

6 Réponses :


17
votes

Le problème n'est pas "où attraper" mais "Que faire quand une exception est attrapée".

Si vous souhaitez vérifier, au lieu d'emballage avec essayez d'attraper code> tu ferais mieux Utilisez P>

    #include <new>
    x = new (std::nothrow) X();
    if (x == NULL) {
        // allocation failed
    }
  • dans un programme non interactif, attrapez au niveau principal et affiche un message d'erreur adéquat. p> li>

  • Dans un programme ayant une boucle d'interaction utilisateur, attrapez également la boucle de sorte que l'utilisateur puisse fermer certaines choses et essayer de continuer. P> li> ul>

    Exceptionnellement, il existe d'autres endroits où une capture est significative, mais c'est rare. p> p>


6 commentaires

En effet, NOTHROW NEW est une option viable, mais s'il y a quelques allocations dans un bloc de code donné, ce sera beaucoup plus verbeux que d'utiliser un bloc d'essai / attraper. Je suis d'accord à 100% que "Que faire" est la vraie question, puisque les scénarios de mémoire limitent vraiment combien vous pouvez faire pour réparer les choses.


Pas tellement "quoi faire", mais "Pouvez-vous faire quelque chose du tout"


Si vous l'attrapez assez haut, une mémoire peut avoir été libérée pendant la déruisement de la pile. Vous pouvez vous assurer que quelque chose est libéré, à l'aide d'un nouveau_handler ou d'astuces comme int flag = false; essayez {vecteur v (1000); Flag = true; DOEventLoop (); } Catch (Bad_alloc) {si (drapeau) COUT << "J'ai 4K à utiliser pour inviter l'utilisateur \ n"; }


Où "invite l'utilisateur" peut signifier de collecter une boîte de dialogue hors de la mémoire et / ou une invite d'enregistrement. Bien sûr sur Linux, vous ne verrez pas Bad_alloc de toute façon, vous obtiendrez une faute de page. Sur n'importe quel système d'exploitation, vous trouverez peut-être que cela mette à une halte avant qu'une application ne voit pas de mémoire, et / ou que la mémoire dans votre processus ne vous aide pas à afficher des dialogues, d'enregistrer des fichiers, etc., car l'interface utilisateur et le noyau peuvent ' t Allouer la mémoire. Mais cela vaut probablement la peine d'essayer au cas où il fonctionne (peut-être parce que votre allocation échouée était d'un gros objet, il y a donc une mémoire libre).


@onebyone, à propos de Linux, fais-vous allusion sur le comportement modifiable en ajustant / proc / sys / vm / overcommit * ou autre chose? (Celui-ci est une défaillance stupide et qu'il devrait s'agir d'une configuration pré-processus et non d'un système large).


Oui, je parle de surmonter. Je ne connais aucune autre raison spécifique pour laquelle votre processus Linux se bloque simplement parce que vous manquez de mémoire. Comme je le disais, cependant, sur n'importe quel système d'exploitation, il y a un risque qui manquant de mémoire causera quelque chose se tromper, même si juste d'autres applications. Vous pouvez donc faire de votre mieux, mais vous ne pouvez pas compter sur cela, ce qui rend la situation recouvrable pour l'utilisateur.



6
votes

Je sais habituellement des exceptions au point où l'utilisateur a lancé une action. Pour l'application de la console, cela signifie dans principal , pour les applications de l'interface graphique, je mettez des gestionnaires dans des endroits tels que des gestionnaires de boutons et tels.

Je pense que cela a peu de sens capturer des exceptions au milieu d'une action, l'utilisateur s'attend généralement à ce que l'opération soit réussie ou échoue complètement.


0 commentaires

11
votes

gérer l'exception lorsque vous peut . Si une allocation échoue et que votre application ne peut pas continuer sans ce morceau de mémoire, pourquoi la peine de vérifier l'erreur?

gérer l'erreur quand il peut manipuler quand il y a un moyen significatif de récupérer. S'il n'y a rien que vous puissiez faire à propos de l'erreur, laissez-le se propager.


2 commentaires

Je voudrais accepter à la fois le vôtre et l'Apogrammer, ils semblent tous les deux être de bonnes réponses. Depuis que Apogrammer était d'abord, j'accepte son.


yup yup. Son est aussi détaillé aussi



0
votes

Poignez-le dans Main () (ou le gestionnaire d'exception de niveau supérieur équivalent dans qt)

La raison est que STD :: Bad_alloc se produit soit lorsque vous épuiser l'espace mémoire (2 ou 3 Go sur des systèmes de 32 bits ne se produit pas sur des systèmes de 64 bits) ou lorsque vous échappez à l'espace de swap. Les allocateurs de tas modernes ne sont pas à l'écoute de l'espace d'échange, ce qui sera donc une mort lente et bruyante - chances que vos utilisateurs vont bien tuer votre application à l'avance, car elle ne répond plus. Et sur Linux, la manipulation de la mémoire OS est si mauvaise par défaut que votre application est susceptible d'être tuée automatiquement.

Alors, il y a peu de choses que vous pouvez faire. Confessez Vous avez un bogue et voyez si vous pouvez enregistrer n'importe quel travail que l'utilisateur a peut-être fait. Pour pouvoir le faire, il est préférable d'abandonner autant que possible. Oui, cela peut en fait perdre une partie de la dernière entrée utilisateur. Mais c'est cette action très susceptible de déclencher la situation de la SOOM. L'objectif est d'enregistrer les données que vous pouvez faire confiance.


0 commentaires

4
votes

Ceci est un fil relativement ancien, mais il est arrivé quand je cherchais des considérations "std :: bad_alloc" lors de la nouvelle / Supprimer primer ici en 2012.

Je ne prendrais pas le concept "Oh bien rien que vous puissiez faire de toute façon" comme une option viable. J'utilise personnellement dans mes propres allocations le "if (alloc ()) {} else {error / manipulation}" Mentionné ci-dessus. De cette façon, je peux bien gérer et, ou, ou, signaler chaque cas dans leur propre contexte significatif.

Maintenant, d'autres solutions possibles sont: 1) Remplacez le nouveau / Supprimer pour l'application dans laquelle vous pouvez ajouter votre propre manipulation de la mémoire.

Bien que comme d'autres affiches d'affiches, et en particulier avec la connaissance des contextes particuliers, l'option principale est probablement de couper l'application. Si tel est le cas, vous voudrez que votre gestionnaire ait prévenu préallocé, il était nécessaire de mémoire, et, ou, ou, utilisez la mémoire statique, espérons-le donc le gestionnaire qu'il ne soit pas épuisé.

Ici, vous pourriez avoir au moins peut-être une boîte de dialogue sur laquelle figurer et dire quelque chose sur les lignes de: "L'application a manqué de mémoire. Cette erreur fatale et doit maintenant se terminer. L'application doit être exécutée dans les exigences minimales de la mémoire système. Envoyez des rapports de débogage à XXXX ». Le gestionnaire pourrait également sauvegarder tout travail en cours, etc., ajustement de l'application.

En tout cas, vous ne voudrez pas utiliser cela pour quelque chose de critique comme (Avertissement, humour amateur à venir): la navette spatiale, un moniteur de fréquence cardiaque, une machine de dialyse rénale, etc. Ces choses nécessitent des solutions beaucoup plus robustes bien sûr, en utilisant des coffres-forts d'échec, des méthodes de collecte des ordures d'urgence, des tests de 100% / débogage / floues, etc.

2) Semblable au premier, définissez le Global "Set_New_Handler ()" avec un gestionnaire de votre choix pour attraper la condition de mémoire à une portée globale. Peut au moins gérer les choses comme mentionne dans # 1.


0 commentaires

1
votes

La vraie question est la réalité devrait vous attrapez STD :: Bad_Alloc Exceptions? I La plupart des cas si vous manquez de mémoire, vous êtes condamné quand même et que vous pourriez envisager de mettre fin à votre programme.


0 commentaires