The macros LIBTHROWABLE_TRACE, LIBTHROWABLE_TRACE_MSG and LIBTHROWABLE_TRACE_VAR have been revisited an no longer have to be called like
LIBTHROWABLE_TRACE_WITH_MSG(someStupidButUniqueName, "The world is broken and fixing it failed!");
LIBTHROWABLE_TRACE_MSG("Gordon doesn't need to hear all this...");
Finally, there is some incomplete/experimental stuff that you might want to comment on. However, you are strongly discouraged to use features contained in Experimental/Incomplete in real world application, as they might see radical changes or might even be removed completely in future releases.
Gentoo Linux (amd64) | gcc-3.3.6 | gcc-4.1.2 | gcc-4.2.2 | icc-10.0.26 |
Gentoo Linux (x86) | gcc-4.1.2 | icc-10.0.26 | ||
Scientific Linux 4.4 (x86_64) | gcc-3.4.6 | gcc-4.1.0 | ||
Debian Linux 3.1 (amd64) | gcc-3.3.6 |
#include <libthrowable.h> #include <iostream> #include <cstdlib> #include <ctime> using namespace std; namespace lth = libthrowable; namespace { void thisFunctionMayFail() { unsigned val = rand()%8; if(val == 0) throw lth::Error(LIBTHROWABLE_HERE, "fatal error dected"); else if(val == 1) throw lth::Problem(LIBTHROWABLE_HERE, "a problem has occured"); else if(val == 2) throw lth::Exception(LIBTHROWABLE_HERE, "val == 2"); } } int main() { // calling init might not be neccesairy, but better save than sorry lth::init(); srand(time(NULL)); for(unsigned i=0; i != 8; ++i) { try { thisFunctionMayFail(); } catch(const lth::Throwable& th) { cerr << "** Throwable caught in main():" << endl; cerr << th << endl; } } }
#include <libthrowable.h> #include <cstdlib> #include <ctime> #include <iostream> using namespace std; namespace lth = libthrowable; namespace { namespace tags { struct MeltdownTag { static const string& name() { static const string ret("Meltdown"); return ret; } }; struct CoolingSystemLeakageTag { static const string& name() { static const string ret("CoolingSystemLeakage"); return ret; } }; struct MinorOperatingErrorTag { static const string& name() { static const string ret("MinorOperatingError"); return ret; } }; } typedef lth::ThrowableType<lth::Error, tags::MeltdownTag> Meltdown; typedef lth::ThrowableType<lth::Problem, tags::CoolingSystemLeakageTag> CoolingSystemLeakage; typedef lth::UserFaultType<lth::UserFault, tags::MinorOperatingErrorTag> MinorOperatingError; void runNuclearReactorForOneYear() { if(rand()%2 == 0) throw MinorOperatingError(LIBTHROWABLE_HERE, "Everything is under control!"); if(rand()%8 == 0) throw CoolingSystemLeakage(LIBTHROWABLE_HERE); if(rand()%100 == 0) throw Meltdown(LIBTHROWABLE_HERE); } } int main() { // calling init might not be neccesairy, but better save than sorry lth::init(); srand(time(NULL)); try { for(unsigned i=0; i != 20; ++i) { try { runNuclearReactorForOneYear(); } catch(const lth::UserFault& uf) { cerr << uf << endl; } catch(const lth::Problem& pr) { cerr << pr << endl; } } } catch(const lth::Error& err) { cerr << err << endl; return -666; } }
LIBTHROWABLE_TRACE_MSG(msg);
LIBTHROWABLE_TRACE_VAR(var);
libthrowable::TracePoint LIBTHROWABLE_UNIQUE_ID(LIBTHROWABLE_HERE, var, "var name");
#include <libthrowable/init.h> #include <libthrowable/macros/trace.h> using libthrowable::util::stringify; namespace { class PleaseHelpImBuggy { public: PleaseHelpImBuggy() { LIBTHROWABLE_TRACE_MSG("constructing ..."); } PleaseHelpImBuggy(const PleaseHelpImBuggy&) { LIBTHROWABLE_TRACE_MSG("copying ..."); } PleaseHelpImBuggy& operator=(const PleaseHelpImBuggy&) { LIBTHROWABLE_TRACE_MSG("assigning ..."); return *this; } void whatTheHellHappensHere() { LIBTHROWABLE_TRACE(); buggyPrivateMethod(); LIBTHROWABLE_TRACE(); } ~PleaseHelpImBuggy() { LIBTHROWABLE_TRACE_MSG("destroying ..."); } private: void buggyPrivateMethod() { LIBTHROWABLE_TRACE(); anotherBuggyAndPrivateMethod(); LIBTHROWABLE_TRACE(); } void anotherBuggyAndPrivateMethod() { LIBTHROWABLE_TRACE_MSG("entering for loop ..."); for(unsigned i=0; i != 5; ++i) LIBTHROWABLE_TRACE_VAR(i); LIBTHROWABLE_TRACE_MSG("left for loop ..."); } }; }//local namespace int main() { // strictly speaking, calling init is not neccesairy here // as it doesn't affect trace points but only // operator<<(ostream&, const Throwable&) and // operator<<(sotream& const UserFault&), but it does not do any harm // neither and is good practice libthrowable::init(); LIBTHROWABLE_TRACE(); PleaseHelpImBuggy fullOfBugs1; PleaseHelpImBuggy fullOfBugs2(fullOfBugs1); PleaseHelpImBuggy fullOfBugs3; fullOfBugs3 = fullOfBugs1; fullOfBugs3.whatTheHellHappensHere(); }
#include <libthrowable.h> #include <pthread.h> #include <unistd.h> #include <iostream> using namespace libthrowable; using namespace std; namespace { unsigned long int val1 = 0; unsigned long int val2 = 0; void* managerThread(void *p_val); void* workerThread(void *p_val); void* managerThread(void *p_val) { LIBTHROWABLE_TRACE_MSG("entering manager thread ..."); try { pthread_t childThread; int rp = pthread_create(&childThread, NULL, workerThread, p_val); LIBTHROWABLE_ASSERT(rp == 0); sleep(1); rp = pthread_cancel(childThread); LIBTHROWABLE_ASSERT(rp == 0); } catch(const Throwable& th) { cerr << th << endl; abort(); } LIBTHROWABLE_TRACE_MSG("leaving manager thread ..."); pthread_exit(NULL); } void* workerThread(void *p_val) { LIBTHROWABLE_TRACE_MSG("entering worker thread ..."); try { int rp = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); LIBTHROWABLE_ASSERT(rp == 0); rp = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); LIBTHROWABLE_ASSERT(rp == 0); unsigned long int *p_long = static_cast<unsigned long int*>(p_val); LIBTHROWABLE_TRACE_MSG("go ... "); while(true) { ++(*p_long); if((*p_long) % 10000000 == 0) LIBTHROWABLE_TRACE_VAR(*p_long); pthread_testcancel(); } } catch(const Throwable& th) { cerr << th << endl; abort(); } pthread_exit(NULL); } }//local namespace int main() { try { pthread_t thread1, thread2; int rp1 = pthread_create(&thread1, NULL, managerThread, &val1); int rp2 = pthread_create(&thread2, NULL, managerThread, &val2); LIBTHROWABLE_ASSERT(!rp1 && !rp2); rp1 = pthread_join(thread1, NULL); rp2 = pthread_join(thread2, NULL); LIBTHROWABLE_ASSERT(!rp1 && !rp2); cout << "val1: " << val1 << endl; cout << "val2: " << val2 << endl; cout << "winner: " << ((val1 > val2) ? "thread1" : "thread2") << endl; } catch(const Throwable& th) { cout << th << endl; return -1; } }
#include <iostream> #include <libthrowable.h> using namespace libthrowable; using namespace std; using libthrowable::util::stringify; using libthrowable::util::addIndent; namespace { //define a new exception class namespace tags { struct SecuritySubsystemFailureTag { static const string& name() { static const string ret("SecuritySubsystemFailure"); return ret; } }; }//namespace tags typedef ThrowableType<Exception, tags::SecuritySubsystemFailureTag> SecuritySubsystemFailure; namespace a_very_long { namespace namespace_nested { template<class T_NUM> string functionName(const T_NUM& arg1, const string& arg2, const string& arg3) { LIBTHROWABLE_ASSERT(arg1 != 666); return string(stringify(arg1) + " " + arg2 + " " + arg3); } }}//namespaces class BankAccount { public: BankAccount(int sId) : _sId(sId), _access(false) { LIBTHROWABLE_TRACE_MSG("constructing account with sId " + stringify(_sId)); } bool logIn(int sId) { LIBTHROWABLE_TRACE_MSG("attempting to log in with sId " + stringify(sId)); if(sId == _sId) { LIBTHROWABLE_TRACE_MSG("access granted for sId " + stringify(_sId)); _access = true; return true; } LIBTHROWABLE_TRACE_MSG("access denied for sId " + stringify(_sId)); _access = false; return false; } bool drawMoney(int sum) { LIBTHROWABLE_TRACE_MSG("attemting to draw " + stringify(sum) + " from account " + stringify(_sId)); if(!_access) { LIBTHROWABLE_TRACE_MSG("not authorized; request rejected"); return false; } try { return verifyId(); } catch(const Throwable& th) { _access = false; string message = "the security subsystem has encountered a serious error ! " "For security reasons access has been reverted\n" "Security system response:\n" + addIndent(th.what(), 2); throw SecuritySubsystemFailure(LIBTHROWABLE_HERE, message); } } bool logOut() { LIBTHROWABLE_TRACE_MSG("logout for sId " + stringify(_sId)); if(!_access) { LIBTHROWABLE_TRACE_MSG("not loged in; ignoring"); return false; } LIBTHROWABLE_TRACE_MSG("ok"); return true; } private: bool verifyId() { LIBTHROWABLE_TRACE(); doDamnRecursiveStuff1(); return true; } void doDamnRecursiveStuff1(); void doDamnRecursiveStuff2(); void doDamnRecursiveStuff3(); int _sId; bool _access; }; void BankAccount::doDamnRecursiveStuff1() { LIBTHROWABLE_TRACE(); static unsigned recCount = 0; ++recCount; if(recCount == 4) a_very_long::namespace_nested::functionName(666, "argzett", "und weh"); LIBTHROWABLE_TRACE_MSG("starting new recursion"); doDamnRecursiveStuff2(); } void BankAccount::doDamnRecursiveStuff2() { doDamnRecursiveStuff3(); LIBTHROWABLE_TRACE(); } void BankAccount::doDamnRecursiveStuff3() { LIBTHROWABLE_TRACE(); doDamnRecursiveStuff1(); LIBTHROWABLE_TRACE(); } }//unnamed namespace int main() { // calling init might not be neccesairy, but better save than sorry init(); try { BankAccount acc(-1); acc.logIn(1 << 10); acc.logIn(-1); acc.drawMoney(100000); } catch(const Throwable& th) { cerr << th << endl; } }