Boost Development Guide-4.9Ausnahme

Ausnahme

Ausnahmen stellen einen wichtigen Mechanismus für die Fehlerbehandlung in C++ dar. Sie ändern den herkömmlichen Verarbeitungsmodus der Verwendung von Fehlerrückgabewerten, vereinfachen die Funktionsschnittstelle und den Aufrufcode und helfen beim Schreiben sauberer, eleganter und robuster Programme. Der C++-Standard definiert die Standardausnahmeklasse std::Exception und eine Reihe von Unterklassen, die die Grundlage für die Fehlerbehandlung in der gesamten C++-Sprache bilden.
Die boost.Exception-Bibliothek wurde verstärkt, um die Mängel der Ausnahmeklassen in der Standardbibliothek zu beheben. Sie ermöglicht eine Überladung des <<-Operators, der beliebige Daten an die Ausnahme übergeben kann, was dazu beiträgt, die Information und Ausdruckskraft der Ausnahme zu erhöhen Einige seiner Funktionen wurden in den C++11-Standard aufgenommen.

Die Ausnahme befindet sich im Namespace Boost. Um die Ausnahme zu verwenden, müssen Sie die Header-Datei <boost/Exception/all.hpp> einschließen, das heißt:

#include<boost/exception/all.hpp>
using namespace boost;

Ausnahmen in der Standardbibliothek

Um boost.Exception verwenden zu können, müssen wir zunächst das im C++-Standard festgelegte Ausnahmesystem verstehen.

Der C++-Standard definiert eine Ausnahmebasisklasse std::Exception und einen Try/Catch/Throw-Ausnahmebehandlungsmechanismus. std::Exception leitet mehrere Unterklassen ab, um verschiedene Arten von Ausnahmen zu beschreiben, wie etwa bad_alloc, bad_cast, out_of_range usw. Gemeinsam haben wir die erstellt C++-Framework für die Ausnahmebehandlung.

C++ erlaubt das Auslösen eines beliebigen Typs als Ausnahme, aber nachdem std::Exception erscheint, sollten wir versuchen, es zu verwenden, da std::Exception eine sehr nützliche Member-Funktion what() bereitstellt, die die von der Ausnahme enthaltenen Informationen zurückgeben kann. Dies ist besser und sicherer, als einfach einen ganzzahligen Fehlerwert oder eine Zeichenfolge auszulösen.

Wenn std::Exception und seine Unterklassen die Anforderungen des Programms an die Ausnahmebehandlung nicht erfüllen können, können wir es auch erben und weitere Informationen zur Ausnahmediagnose hinzufügen. Wenn Sie beispielsweise Fehlercodeinformationen zu einer Ausnahme hinzufügen möchten, können Sie Folgendes tun:

class my_exception : public std::logic_error  //继承标准库异常类
{
    
    
private:
   int err_no;  //错误码信息
public:
   my_exception(const char* msg, int err) :  //构造函数
    std::logic_error(msg), err_no(err) {
    
    }  //初始化父类和错误码信息
   int get_err_no() //获取自定义的错误码信息
   {
    
     return err_no; }
};

Wenn jedoch viele verschiedene Arten von Ausnahmen im System erforderlich sind, wird diese Implementierungsmethode schnell zu einer großen Belastung für den Programmierer – es muss eine große Menge sehr ähnlicher Code geschrieben werden, um die unterschiedlichen Informationen unterzubringen.

Und bei dieser Lösung gibt es immer noch ein Problem: Wenn eine Ausnahme auftritt, können häufig keine vollständigen Diagnoseinformationen über die Ausnahme abgerufen werden, und sobald die Ausnahmeklasse der Standardbibliothek ausgelöst wird, wird sie zu einem „toten“ Objekt und das Programm verliert die Kontrolle darüber. Kontrollfähigkeit, Sie können sie nur verwenden oder eine neue Ausnahme auslösen.

boost.Exception definiert eine neue Ausnahmeklasse boost::Exception, um diese Mängel zu beheben und den C++-Standard-Ausnahmebehandlungsmechanismus zu verbessern.

Wenn in der folgenden Diskussion über Ausnahmen gesprochen wird, beziehen sich diese, sofern nicht anders angegeben, alle auf boost::Exception. Ausnahmen in der Standardbibliothek verwenden die Form von std::Exception.

Zusammenfassung der Klasse

Die Ausnahmebibliothek stellt zwei Klassen bereit: Ausnahme und Fehlerinfo, die die Grundlage der Ausnahmebibliothek bilden.

class exception
{
    
    
protected:
   exception();
   exception(exception const & x);
   virtual ~exception();
private :
   template <class E, class Tag, class T>
   friend E const & operator<<(E const &, error_info<Tag,T> const &);
};
typename value_type* get_error_info(E & x);

Die Ausnahmeklasse verfügt über wenige öffentliche Mitgliedsfunktionen (aber eine große Anzahl privater Funktionen und Variablen für die interne Implementierung), und der geschützte Konstruktor zeigt seine Entwurfsabsicht: Es handelt sich um eine abstrakte Klasse, auf die niemand außer ihren Unterklassen zugreifen kann. Das kann nicht der Fall sein erstellt oder zerstört, wodurch sichergestellt wird, dass die Ausnahme nicht missbraucht werden kann.

Die wichtige Fähigkeit der Ausnahme liegt in ihrem Freundoperator <<, der Informationen über das error_info-Objekt speichern kann. Die gespeicherten Informationen können get_error_info<>()jederzeit mit einer kostenlosen Funktion abgerufen werden. Diese Funktion gibt einen Zeiger zum Speichern der Daten oder einen Nullzeiger zurück, wenn die Ausnahme keine solchen Informationen enthält.

Die Ausnahme erbt absichtlich nicht von std::Exception, da in Wirklichkeit ein großer Teil des vorhandenen Codes bereits über viele Unterklassen von std::Exception verfügt. Wenn die Ausnahme auch eine Unterklasse von std::Exception ist, kann die Verwendung der Vererbung für die Ausnahme zu Problemen führen Mehrfachvererbungsproblem „Diamant“.

template <class Tag, class T>
class error_info
{
    
    
public:
   typedef T value_type;
   error_info(value_type const &v);
   value_type & value();
};

error_info bietet eine allgemeine Lösung zum Hinzufügen von Informationen zu Ausnahmetypen. Der erste Vorlagentypparameter Tag ist ein Tag. Normalerweise (vorzugsweise) handelt es sich um eine leere Klasse, die nur dazu dient, die Klasse „error_info“ zu markieren, damit sie bei der Instanziierung der Vorlage einen anderen Typ generiert. Der zweite Vorlagentypparameter T sind die tatsächlich gespeicherten Informationsdaten, auf die mit der Memberfunktion value() zugegriffen werden kann.

Übergeben Sie Informationen an die Ausnahme

„Exception“ und „error_info“ sind für die Zusammenarbeit mit „std::Exception“ konzipiert, und benutzerdefinierte Ausnahmeklassen können problemlos von „Exception“ und „STD::Exception“ mehrfach erben, um die Funktionen beider zu nutzen.

Da die Ausnahme als abstrakte Klasse definiert ist, muss unser Programm ihre Unterklasse definieren, um sie zu verwenden. Wie oben erwähnt, muss die Ausnahme virtuelle Vererbung verwenden. Normalerweise ist die Implementierung der benutzerdefinierten Ausnahmeklasse nach Abschluss der Vererbung abgeschlossen. Es besteht keine Notwendigkeit, Mitgliedsvariablen oder Mitgliedsfunktionen „überflüssig“ hinzuzufügen. Diese Aufgaben wurden bereits von der Ausnahme abgeschlossen. Zum Beispiel:

struct my_exception : //自定义异常类
virtual std::exception, //虚继承,struct默认public继承
virtual boost::exception //虚继承,struct默认public继承
{
    
    }; //空实现,不需要实现代码

Als nächstes müssen wir die Informationen definieren, die für die Ausnahme gespeichert werden müssen – mithilfe der Vorlagenklasse error_info. Verwenden Sie eine Struktur als ersten Vorlagenparameter, um den Informationstyp zu markieren, und verwenden Sie dann den zweiten Vorlagenparameter, um den Datentyp der Informationen anzugeben. Da error_info<>die Typdefinition lang ist, ist es aus Gründen der Benutzerfreundlichkeit normalerweise erforderlich, typedef zu verwenden.

Der folgende Code verwendet error_info, um zwei Informationsklassen zu definieren, die int und string speichern:

int main()
try  //function-try块
{
    
    
	try
	{
    
    

		throw my_exception() << err_no(10); //抛出异常,存储错误码
	}
	catch (my_exception& e) //捕获异常,使用引用形式
	{
    
    

		cout << *get_error_info<err_no>(e) << endl;
		cout << e.what() << endl;
		e << err_str("other info"); //向异常追加信息
		throw; //再次抛出异常
	}
}
catch (my_exception& e) //function-try的捕获代码
{
    
    
	cout << *get_error_info<err_str>(e) << endl; //获得异常信息
}

Die Kommentare im Code haben viele Dinge erklärt, schauen wir uns das noch einmal an.

Das Programm definiert zunächst eine Ausnahmeklasse my_Exception und verwendet dann typedef, um zwei Arten von Ausnahmeinformationen zu definieren: err_no und err_str, und verwendet int und string, um den Fehlercode bzw. die Fehlerinformationen zu speichern. Die Funktion main () verwendet den Funktions-Try-Block, um Ausnahmen abzufangen. Sie enthält den gesamten Funktionskörper im Try-Block, wodurch der Ausnahmebehandlungscode besser vom normalen Prozesscode getrennt werden kann.

Die Anweisung „throw my_Exception()“ erstellt ein temporäres Objekt der Ausnahmeklasse „my_Exception“ und verwendet sofort <<, um das Objekt „err_no“ daran zu übergeben und den Fehlercode 10 zu speichern. Anschließend wird die Ausnahme vom Catch-Block abgefangen, und die freie Funktion get_error_info<err_no>(e)kann den Zeiger auf den in der Ausnahme gespeicherten Informationswert abrufen. Daher muss auf sie mit dem Dereferenzierungsoperator * zugegriffen werden.

Ausnahmen können auch mit Informationen angehängt werden, ebenfalls mit dem Operator <<. Schließlich wird im Catch-Block-Teil von function-try die Ausnahme endgültig behandelt und das Programm beendet.

Fehlermeldungsklasse

Anhand von Beispielen erhalten wir ein grundlegendes Verständnis für die Verwendung von Ausnahmen. Wir können sehen, dass die Verwendung von Ausnahmen recht klar und einfach ist und gleichzeitig flexible und leistungsstarke Funktionen bietet, wodurch die Ausnahmeklasse nützlicher wird.

Da die von der Ausnahme abgeleitete Ausnahmeklassendefinition sehr einfach ist und keinen Implementierungscode enthält, können Sie problemlos ein ausgefeiltes und vollständiges Ausnahmeklassensystem einrichten, das für Ihr eigenes Programm geeignet ist, sodass jede Ausnahmeklasse nur einem Fehlertyp entspricht. Solange virtuelle Vererbung verwendet wird, kann das Klassensystem beliebig komplex sein, um die Bedeutung des Fehlers vollständig auszudrücken.

Eine weitere wichtige Aufgabe bei der Behandlung von Ausnahmen ist die Definition des Fehlerinformationstyps. Die grundlegende Methode besteht darin, typedef zu verwenden, um die Vorlagenklasse error_info zu konkretisieren. Dies ist oft umständlich, insbesondere wenn es eine große Anzahl von Nachrichtentypen gibt. Daher stellt die Ausnahmebibliothek speziell eine Reihe vordefinierter Fehlermeldungsklassen bereit, z. B. „logic_err“ und andere von der Standardbibliothek definierte Typen, um Programmierern die Verwendung zu erleichtern:

typedef error_info<...> errinfo_api_function;
typedef error_info<...> errinfo_at_iine;
typedef error_info<...> errinfo_errno;
typedef error_info<...> errinfo_file_handle;
typedef error_info<...> errinfo_file_name;
typedef error_info<...> errinfo_file_open_mode;
typedef error_info<...> errinfo_type_info_name;

Sie können zur Verarbeitung von Fehlerinformationen wie allgemeinen API-Aufrufen, Zeilennummern, Fehlercodes, Dateihandles, Dateinamen usw. verwendet werden. Zum Beispiel:

try
{
    
    
     throw my_exception() << errinfo_api_function("call api")
           << errinfo_errno(101);
}
catch (boost::exception& e)
{
    
    
     cout << *get_error_info<errinfo_api_function>(e);
     cout << *get_error_info<errinfo_errno>(e);
}    

Darüber hinaus stellt die Ausnahmebibliothek auch drei vordefinierte Fehlermeldungstypen bereit, die Benennungsregeln unterscheiden sich jedoch geringfügig:

typedef error_info<...>  throw_function;
typedef error_info<...>  throw_file;
typedef error_info<...>  throw_line;

Diese drei Fehlermeldungstypen werden hauptsächlich zum Speichern von Quellcodeinformationen verwendet. Mit den Makros BOOST_CURRENT_FUNCTION, _FILE_ und _LINE_ können Sie den Namen der aufrufenden Funktion, den Namen der Quelldatei und die Nummer der Quellcodezeile abrufen.

Wenn diese vordefinierten Klassen die Anforderungen jedoch nicht erfüllen können, müssen wir erneut typedef verwenden. Um dieses kleine Problem zu lösen, können wir ein Hilfstool-Makro DEFINE_ERROR_INPO anpassen, mit dem die Definition von error_info schnell und einfach implementiert werden kann:

#define DEFINE_ERROR_INFO(type, name) \
   typedef boost::error_info<struct tag_##name, type> name

Das Makro DEFINE_ERROR_INFO akzeptiert zwei Parameter: Typ ist der Typ, den es speichern möchte, und Name ist der erforderliche Name des Fehlermeldungstyps. Verwenden Sie den Vorverarbeitungsbefehl ##, um die für error_info erforderliche Label-Klasse zu erstellen. Die Verwendung ist so einfach wie die Deklaration einer Variablen:

DEFINE_ERROR_INFO(int, err_no);

Nach der Makroerweiterung entspricht es:

typedef boost::error_info<struct tag_err_no, int> err_no;

Ungewöhnliche Verpackungsstandards

Die Ausnahmebibliothek stellt eine Vorlagenfunktion „enable_error_info(T &e)“ bereit, wobei T eine Standardausnahmeklasse oder ein anderer benutzerdefinierter Typ ist. Es kann den Typ T umschließen, um eine von boost::Exception und T abgeleitete Klasse zu generieren und so alle Vorteile von boost::Exception zu nutzen, ohne das ursprüngliche Ausnahmebehandlungssystem zu ändern. Wenn Typ T bereits eine Unterklasse von boost::Exception ist, gibt enable_error_info eine Kopie von e zurück.

enable_error_info() wird normalerweise verwendet, wenn Ausnahmeklassen bereits im Programm vorhanden sind und es schwierig oder sogar unmöglich ist, diese Ausnahmeklassen zu ändern (z. B. wenn sie in eine Bibliothek kompiliert wurden). Zu diesem Zeitpunkt kann enable_error_info() die ursprüngliche Ausnahmeklasse umschließen, wodurch es einfach ist, boost::Exception in das ursprüngliche Ausnahmesystem zu integrieren, ohne vorhandenen Code zu ändern.

Der Code, der die Verwendung von enable_error_info() demonstriert, lautet wie folgt:

struct my_err {
    
    }; //某个自定义的异常库,未使用boost::exception

int main()
{
    
    
	try
	{
    
    
	    //使用enable_error_info包装自定义异常
		throw enable_error_info(my_err()) << errinfo_errno(10);
	}
	catch (boost::exception& e) //这里必须使用boost::exception来捕获
	{
    
    
		cout << *get_error_info<errinfo_errno>(e) << endl;
	}
}

Achten Sie auf die Verwendung von „catch“ im Code. Das von „enable_error_info()“ zurückgegebene Objekt ist eine Unterklasse von „boost::Exception“ und „my_err“. Der Parameter von „catch“ kann einer der beiden sein, wenn Sie jedoch die von „gespeicherten“ Informationen verwenden möchten boost::Exception, Sie müssen boost::Exception verwenden, um Ausnahmen abzufangen.

enable_error_info() kann auch Standardbibliotheksausnahmen umschließen:

throw enable_error_info(std::runtime_error("runtime"))
                  << errinfo_at_line(_LINE_); //包装标准异常

Verwenden einer Funktion zum Auslösen einer Ausnahme

Die Ausnahmebibliothek fügt Ausnahmen viele neue Funktionen hinzu und bringt viele Vorteile mit sich. Aus verschiedenen Gründen können die Ausnahmeklassen im Programm jedoch nicht immer von boost::Exception erben und müssen mit enable_error_info() gepackt werden.

Die Ausnahmebibliothek stellt die Funktion „throw_Exception()“ in der Header-Datei <boost/throw_Exception.hpp> bereit, um den Aufruf von „enable_error_info()“ zu vereinfachen. Sie kann die ursprüngliche „throw“-Anweisung zum Auslösen einer Ausnahme ersetzen und automatisch „enable_error_info()“ verwenden, um die Ausnahme einzuschließen Objekt und unterstützt Thread-Sicherheit, was besser ist als die direkte Verwendung von throw, äquivalent zu:

throw (boost::enable_error_info(e))

Dadurch wird sichergestellt, dass die ausgelöste Ausnahme eine Unterklasse von boost::Exception ist und Ausnahmeinformationen angehängt werden können. Zum Beispiel:

throw_exception (std::runtime_error("runtime"));

Basierend auf throw_Exception() stellt die Ausnahmebibliothek ein sehr nützliches Makro BOOST_THROW_EXCEPTION bereit, das boost::throw_Exception() und enable_error_info() aufruft, sodass sie jeden Ausnahmetyp akzeptieren und throw_function, throw_file und throw_line verwenden kann, um automatisch Informationen hinzuzufügen, z B. Funktionsname, Dateiname und Zeilennummer, in der die Ausnahme aufgetreten ist.

Es ist jedoch zu beachten, dass zur Gewährleistung der Kompatibilität mit dem Konfigurationsmakro BOOST_NO_EXCEPTIONS sowohl die Funktion throw_Exception() als auch das Makro BOOST_THROW_EXCEPTION erfordern, dass der Parameter e eine Unterklasse von std::Exception sein muss.

Für neu geschriebene Ausnahmeklassen ist dies normalerweise kein Problem, da sie immer von std::Exception und boost::Exception erben. Wenn es jedoch nicht von std::Exception abgeleitete Ausnahmen im alten Code gibt, können diese nicht verwendet werden, was bedeutet ist sicher. Dies schränkt den Anwendungsbereich von throw_Exception() und BOOST_NO_EXCEPTIONS in gewissem Maße ein.

Wenn Sie sicherstellen, dass Sie in Ihrem Programm immer boost::Exception verwenden und nicht das Konfigurationsmakro BO0ST_NO_EXCEPTIONS definieren (dies sollte in den meisten Fällen der Fall sein), können Sie den Boost-Quellcode ändern und throw_Exception_assert_compatibility(e) in <boost/ auskommentieren. throw_Exception.hpp> Diese Anweisung entfernt diese Einschränkung.

Erhalten Sie weitere Debugging-Informationen

Eine Ausnahme bietet die Möglichkeit, Informationen bequem zu speichern. Sie können eine beliebige Menge an Informationen hinzufügen, aber wenn das Ausnahmeobjekt mit dem Operator<< mehrmals mit Daten angehängt wird, führt dies dazu, dass eine große Menge an Informationen gespeichert wird (BOOST_THROW_EXCEPTION ist ein gutes Beispiel). Wenn wir immer noch die kostenlose Funktion get_error_info verwenden, um Element für Element abzurufen, kann dies mühsam oder sogar unmöglich sein. In diesem Fall benötigen wir eine andere Funktion: Diagnostic_information().

Diagnostic_information() kann alle in der Ausnahme enthaltenen Informationen ausgeben. Wenn die Ausnahme vom Makro BOOST_THROW_EXCEPTION ausgelöst wird, ist sie möglicherweise recht groß und nicht benutzerfreundlich, kann aber Programmentwicklern gute Diagnosefehlerinformationen liefern.

Der Code, der die Verwendung von BOOST_THROW_EXCEPTION und Diagnostic_information() demonstriert, lautet wie folgt:

struct my_err() //自定义的异常类

int main()
{
    
    
	try
	{
    
    
	    //使用enable_error_info包装自定义异常
		throw enable_error_info(my_err())
			<< errinfo_errno(101)
			<< errinfo_api_function("fopen");
	}
	catch (boost::exception& e)
	{
    
    
		cout << diagnostic_information(e) << endl;
	}

	try
	{
    
    
		BOOST_THROW_EXCEPTION(std::logic_error("logic")); //必须是标准异常
	}
	catch (boost::exception& e)
	{
    
    
		cout << diagnostic_information(e) << endl;
	}
}

Die laufenden Ergebnisse zeigen den Unterschied zwischen gewöhnlichen Throw-Anweisungen und BOOST_THROW_EXCEPTION, die weitere nützliche Informationen zum Debuggen anzeigen können.

Es gibt auch eine praktischere Funktion current_Exception_diagnostic_information() in der Ausnahmebibliothek. Sie kann nur innerhalb des Catch-Blocks verwendet werden und gibt die Ausnahmediagnosezeichenfolge als std::string zurück. Dadurch entfällt die kleine Mühe, Ausnahmeparameter anzugeben.

Verpackung von Ausnahmeinformationen

Exception unterstützt die Verwendung von boost::tuple zum Kombinieren und Packen von Ausnahmeinformationen. Wenn es viele Arten von Ausnahmeinformationen gibt und diese häufig in Gruppen erscheinen, kann dies das Schreiben ausgelöster Ausnahmen vereinfachen. Zum Beispiel:

//tuple类型定义
typedef tuple<errinfo_api_function, errinfo_errno> err_group;
try
{
    
    
    //使用enable_error_info包装自定义异常
    throw enable_error_info(std::out_of_range("out"))
        << err_group("syslogd", 874);
}
catch (boost::exception&)
{
    
    
    cout << current_exception_diagnostic_information() << endl;
}

Typkonvertierung

Die Vorlagenfunktion current_exception_cast<E>()bietet eine Konvertierungsoperation ähnlich der Standardbibliothek. Sie ähnelt current_Exception_diagnostic_information() und kann nur innerhalb des Catch-Blocks verwendet werden. Sie kann das Ausnahmeobjekt in einen Zeiger auf den Typ E konvertieren. Wenn das Ausnahmeobjekt nicht konvertiert werden kann in E* wird ein Nullzeiger zurückgegeben. .

Der folgende Code wandelt beispielsweise boost::Exception in std::Exception um, vorausgesetzt, die Ausnahme muss eine Unterklasse von std::Exception sein:

catch (boost::exception&)
{
    
    
    cout << current_exception_cast<std::exception>()->what();
}

Zwischen Threads übergebene Ausnahmen

Die Ausnahmebibliothek unterstützt die Weitergabe von Ausnahmen zwischen Threads, was die Verwendung der Klonfunktion von boost::Exception erfordert. Durch die Verwendung von „enable_current_Exception()“ zum Umschließen des Ausnahmeobjekts oder durch die Verwendung von „throw_Exception()“ kann das Ausnahmeobjekt so umschlossen werden, dass es geklont werden kann.

Wenn eine Ausnahme auftritt, muss der Thread die Funktion current_Exception() im Catch-Block aufrufen, um das Zeigerobjekt „Exception_ptr“ des aktuellen Ausnahmeobjekts abzurufen. Es zeigt auf eine Kopie des Ausnahmeobjekts. Es ist threadsicher und kann besessen werden und gleichzeitig von mehreren Threads gleichzeitig geändert werden. rethrow_Exception() kann Ausnahmen erneut auslösen.

Der Code, der die Behandlung von Ausnahmen in einem Thread demonstriert, lautet wie folgt:

void thread_work() //线程工作函数
{
    
    
     throw_exception(std::exception("test"));
}
int main()
{
    
    
     try
     {
    
    
         thread_work();
     }
     catch(...)
     {
    
    
          exception_ptr e = current_exception();
          cout << current_exception_diagnostic_information();
     }
}

Diese Verwendung von boost::Exception wurde in den C++11-Standard aufgenommen

Codebeispiel

#include <iostream>
using namespace std;

#include <boost/exception/all.hpp>
using namespace boost;
//

class my_exception_test : public std::logic_error
{
    
    
private:
	int err_no;
public:
	my_exception_test(const char* msg, int err) :
		std::logic_error(msg), err_no(err) {
    
    }
	int get_err_no()
	{
    
    
		return err_no;
	}
};

struct my_exception :
	virtual std::exception,
	virtual boost::exception
{
    
    };

typedef boost::error_info<struct tag_err_no, int>     err_no;
typedef boost::error_info<struct tag_err_str, string> err_str;

//
void case1()
try
{
    
    
	try
	{
    
    

		throw my_exception() << err_no(10);
	}
	catch (my_exception& e)
	{
    
    

		cout << *get_error_info<err_no>(e) << endl;
		cout << e.what() << endl;
		e << err_str("other info");
		throw;
	}
}
catch (my_exception& e)
{
    
    
	cout << *get_error_info<err_str>(e) << endl;
}

//
#define DEFINE_ERROR_INFO(type, name) \
    typedef boost::error_info<struct tag_##name, type> name

void case2()
try
{
    
    
	throw my_exception() << errinfo_api_function("call api")
		<< errinfo_errno(101);
}
catch (boost::exception& e)
{
    
    
	cout << *get_error_info<errinfo_api_function>(e);
	cout << *get_error_info<errinfo_errno>(e);
	cout << endl;
}

//
struct my_err {
    
    };

void case3()
{
    
    
	try
	{
    
    
		throw enable_error_info(my_err()) << errinfo_errno(10);
		throw enable_error_info(std::runtime_error("runtime"))
			<< errinfo_at_line(__LINE__);

	}
	catch (boost::exception& e)
	{
    
    
		cout << *get_error_info<errinfo_errno>(e) << endl;
	}
}

//
#include <boost/throw_exception.hpp>

void case4()
{
    
    
	try
	{
    
    
		throw enable_error_info(my_err())
			<< errinfo_errno(101)
			<< errinfo_api_function("fopen");
	}
	catch (boost::exception& e)
	{
    
    
		cout << diagnostic_information(e) << endl;
	}

	try
	{
    
    
		BOOST_THROW_EXCEPTION(std::logic_error("logic"));
	}
	catch (boost::exception& e)
	{
    
    
		cout << diagnostic_information(e) << endl;
	}
}

int main()
{
    
    
	case1();
	case2();
	case3();
	case4();
}

Supongo que te gusta

Origin blog.csdn.net/qq_36314864/article/details/132491947
Recomendado
Clasificación