Frage

Es gibt eine Methode namens foo das gibt manchmal den folgenden Fehler zurück:

terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Abort

Gibt es eine Möglichkeit, wie ich eine verwenden kann try-catch blockieren, um zu verhindern, dass dieser Fehler mein Programm beendet (alles, was ich tun möchte, ist zurückzukehren -1)?

Wenn ja, wie lautet die Syntax dafür?

Wie sonst kann ich damit umgehen bad_alloc in C ++?

War es hilfreich?

Lösung

Sie können es wie jede andere Ausnahme abfangen:

try {
  foo();
}
catch (const std::bad_alloc&) {
  return -1;
}

Was Sie ab diesem Zeitpunkt sinnvoll tun können, liegt bei Ihnen, aber technisch ist es definitiv machbar.

Andere Tipps

Im Allgemeinen Sie kann nicht, und sollte es nicht versuchen, um auf diesen Fehler zu reagieren. bad_alloc gibt an, dass eine Ressource nicht zugewiesen werden kann, da nicht genügend Arbeitsspeicher verfügbar ist.In den meisten Szenarien kann Ihr Programm nicht hoffen, damit fertig zu werden, und ein baldiges Beenden ist das einzig sinnvolle Verhalten.

Schlimmer noch, moderne Betriebssysteme überbelegen häufig:auf solchen Systemen, malloc und new kann ein gültiger Zeiger auch dann angezeigt werden, wenn nicht mehr genügend freier Speicher vorhanden ist – std::bad_alloc wird niemals geworfen oder ist zumindest kein verlässliches Zeichen für Gedächtniserschöpfung.Stattdessen versucht man Zugang der zugewiesene Speicher führt dann zu einem Segmentierungsfehler, der nicht auffangbar ist (Sie können handhaben das Segmentierungsfehlersignal, aber Sie können das Programm danach nicht fortsetzen).

Das einzige, was du beim Fangen tun könntest std::bad_alloc besteht darin, den Fehler möglicherweise zu protokollieren und zu versuchen, einen sicheren Programmabbruch zu gewährleisten, indem ausstehende Ressourcen freigegeben werden (dies geschieht jedoch automatisch im normalen Verlauf des Stapelabwickelns, nachdem der Fehler ausgelöst wurde, wenn das Programm RAII entsprechend verwendet).

In bestimmten Fällen versucht das Programm möglicherweise, Speicher freizugeben und es erneut zu versuchen oder sekundären Speicher (= Festplatte) anstelle von RAM zu verwenden, aber diese Möglichkeiten bestehen nur in ganz bestimmten Szenarien mit strengen Bedingungen:

  1. Die Anwendung muss sicherstellen, dass sie auf einem System ausgeführt wird, das keinen Arbeitsspeicher überbelegt, also.es signalisiert einen Fehler bei der Zuweisung und nicht später.
  2. Die Anwendung muss Speicher freigeben können sofort, ohne weitere zufällige Zuordnungen in der Zwischenzeit.

Es ist äußerst selten, dass Anwendungen die Kontrolle über Punkt 1 — Userspace-Anwendungen haben nie tun Sie, es ist eine systemweite Einstellung, für deren Änderung Root-Berechtigungen erforderlich sind.1

OK, nehmen wir an, Sie haben Punkt 1 fixiert.Was Sie jetzt tun können, ist zum Beispiel eine zu verwenden LRU-Zwischenspeicher für einige Ihrer Daten (wahrscheinlich einige besonders große Geschäftsobjekte, die bei Bedarf neu generiert oder neu geladen werden können).Als nächstes müssen Sie die eigentliche Logik, die möglicherweise fehlschlägt, in eine Funktion einfügen, die Wiederholungsversuche unterstützt — mit anderen Worten, wenn sie abgebrochen wird, können Sie sie einfach neu starten:

lru_cache<widget> widget_cache;

double perform_operation(int widget_id) {
    std::optional<widget> maybe_widget = widget_cache.find_by_id(widget_id);
    if (not maybe_widget) {
        maybe_widget = widget_cache.store(widget_id, load_widget_from_disk(widget_id));
    }
    return maybe_widget->frobnicate();
}

…

for (int num_attempts = 0; num_attempts < MAX_NUM_ATTEMPTS; ++num_attempts) {
    try {
        return perform_operation(widget_id);
    } catch (std::bad_alloc const&) {
        if (widget_cache.empty()) throw; // memory error elsewhere.
        widget_cache.remove_oldest();
    }
}

// Handle too many failed attempts here.

Aber auch hier, mit std::set_new_handler anstatt zu handhaben std::bad_alloc bietet den gleichen Nutzen und wäre viel einfacher.


1 Wenn Sie eine Anwendung erstellen, die tun kontrollpunkt 1, und Sie lesen diese Antwort, bitte schreiben Sie mir eine E-Mail, ich bin wirklich neugierig auf Ihre Umstände.

Was ist das C ++ - Standard spezifizierte Verhalten von new in c ++?

Die übliche Vorstellung ist, dass wenn new der Operator kann keinen dynamischen Speicher der angeforderten Größe zuweisen, dann sollte er eine Ausnahme vom Typ auslösen std::bad_alloc.
Es passiert jedoch noch etwas mehr, noch bevor ein bad_alloc ausnahme wird ausgelöst:

C ++ 03 Abschnitt 3.7.4.1.3: besagt

Eine Zuordnungsfunktion, die keinen Speicher zuweist, kann den aktuell installierten new_handler (18.4.2.2) aufrufen, falls vorhanden.[Beachten:Eine vom Programm bereitgestellte Zuordnungsfunktion kann die Adresse des aktuell installierten new_handler mit der Funktion set_new_handler (18.4.2.3) ermitteln.] Wenn eine Zuordnungsfunktion, die mit einer leeren Ausnahmespezifikation (15.4), throw() , deklariert wurde, keinen Speicher zuweist, muss sie einen Nullzeiger zurückgeben.Jede andere Zuordnungsfunktion, die keinen Speicher zuweist, zeigt einen Fehler nur an, indem sie eine Ausnahme der Klasse std:: bad_alloc (18.4.2.1) oder einer von std:: bad_alloc abgeleiteten Klasse auslöst.

Betrachten Sie das folgende Codebeispiel:

#include <iostream>
#include <cstdlib>

// function to call if operator new can't allocate enough memory or error arises
void outOfMemHandler()
{
    std::cerr << "Unable to satisfy request for memory\n";

    std::abort();
}

int main()
{
    //set the new_handler
    std::set_new_handler(outOfMemHandler);

    //Request huge memory size, that will cause ::operator new to fail
    int *pBigDataArray = new int[100000000L];

    return 0;
}

Im obigen Beispiel, operator new (höchstwahrscheinlich) kann kein Speicherplatz für 100.000.000 Ganzzahlen zugewiesen werden, und die Funktion outOfMemHandler() wird aufgerufen, und das Programm bricht nach ausgabe einer Fehlermeldung.

Wie hier zu sehen ist das Standardverhalten von new operator, wenn eine Speicheranforderung nicht erfüllt werden kann, ist der Aufruf der new-handler funktion wiederholt, bis genügend Speicher gefunden wurde oder keine neuen Handler mehr vorhanden sind.Im obigen Beispiel, es sei denn, wir rufen an std::abort(), outOfMemHandler() wäre wiederholt angerufen.Daher sollte der Handler entweder sicherstellen, dass die nächste Zuweisung erfolgreich ist, oder einen anderen Handler registrieren oder keinen Handler registrieren oder nicht zurückgeben (dh.beenden Sie das Programm).Wenn es keinen neuen Handler gibt und die Zuweisung fehlschlägt, löst der Operator eine Ausnahme aus.

Was ist der new_handler und set_new_handler?

new_handler ist ein typedef für einen Zeiger auf eine Funktion, die nichts akzeptiert und zurückgibt, und set_new_handler ist eine Funktion, die einen Wert annimmt und zurückgibt new_handler.

So etwas wie:

typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();

der Parameter von set_new_handler ist ein Zeiger auf den Funktionsoperator new sollte anrufen, wenn der angeforderte Speicher nicht zugewiesen werden kann.Sein Rückgabewert ist ein Zeiger auf die zuvor registrierte Handlerfunktion oder null, wenn es keinen vorherigen Handler gab.

Wie gehe ich mit Speichermangel in C ++ um?

Angesichts des Verhaltens von newein gut gestaltetes Benutzerprogramm sollte mit Speichermangel umgehen, indem es eine ordnungsgemäße bereitstellt new_handlerwas eine der folgenden Aktionen ausführt:

Stellen Sie mehr Speicher zur Verfügung: Dies kann dazu führen, dass der nächste Speicherzuweisungsversuch innerhalb der Schleife von operator new erfolgreich ist.Eine Möglichkeit, dies zu implementieren, besteht darin, beim Programmstart einen großen Speicherblock zuzuweisen und ihn dann beim ersten Aufruf des neuen Handlers für die Verwendung im Programm freizugeben.

Installieren Sie einen anderen neuen Handler: Wenn der aktuelle New-Handler keinen Speicher mehr zur Verfügung stellen kann und es einen anderen New-Handler gibt, der dies kann, kann der aktuelle New-Handler den anderen New-Handler an seiner Stelle installieren (durch Aufrufen set_new_handler).Wenn operator new das nächste Mal die Funktion new-handler aufruft, wird die zuletzt installierte Funktion abgerufen.

(Eine Variation dieses Themas besteht darin, dass ein neuer Handler sein eigenes Verhalten ändert, sodass er beim nächsten Aufruf etwas anderes tut.Eine Möglichkeit, dies zu erreichen, besteht darin, dass der neue Handler statische, Namespace-spezifische oder globale Daten ändert, die sich auf das Verhalten des neuen Handlers auswirken.)

Deinstallieren Sie den new-handler: Dies geschieht, indem ein Nullzeiger an übergeben wird set_new_handler.Ohne installierten neuen Handler, operator new wird eine Ausnahme auslösen ((konvertierbar in) std::bad_alloc), wenn die Speicherzuweisung nicht erfolgreich ist.

Eine Ausnahme auslösen umwandelbar in std::bad_alloc.Solche Ausnahmen werden nicht erfasst operator new, wird aber an die Site weitergegeben, von der die Speicheranforderung stammt.

Nicht zurück: Durch Anrufen abort oder exit.

Ich würde das nicht vorschlagen, da bad_alloc bedeutet, dass Sie sind nicht genügend Speicher.Es wäre am besten, einfach aufzugeben, anstatt zu versuchen, sich zu erholen.Hier ist jedoch die Lösung, nach der Sie fragen:

try {
    foo();
} catch ( const std::bad_alloc& e ) {
    return -1;
}

Ich kann dafür eine einfachere (und noch schnellere) Lösung vorschlagen. new operator würde null zurückgeben, wenn Speicher nicht zugewiesen werden könnte.

int fv() {
    T* p = new (std::nothrow) T[1000000];
    if (!p) return -1;
    do_something(p);
    delete p;
    return 0;
}

Ich hoffe, das könnte helfen!

Lassen Sie Ihre foo-Programm Ausfahrt auf kontrollierte Weise:

#include <stdlib.h>     /* exit, EXIT_FAILURE */

try {
    foo();
} catch (const std::bad_alloc&) {
    exit(EXIT_FAILURE);
}

Dann schreibe ein shell-Programm das ruft das eigentliche Programm auf.Da die Adressräume getrennt sind, ist der Status Ihres Shell-Programms immer genau definiert.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top