Skip to content

Instantly share code, notes, and snippets.

@karagog
Last active June 18, 2022 05:31
Show Gist options
  • Save karagog/ab41468ea82a8fb54cde to your computer and use it in GitHub Desktop.
Save karagog/ab41468ea82a8fb54cde to your computer and use it in GitHub Desktop.
Try-Catch-Finally in C++
#include <iostream>
#include <exception>
#include <string>
#include "trycatchfinally.h"
using namespace std;
int main()
{
// No exception
TryFinally(
[]{ cout<<"Try Body"<<endl; },
[](exception){ cout<<"Catch Body"<<endl; },
[]{ cout<<"Finally Body"<<endl; }
);
// Exception thrown
TryFinally(
[]{ cout<<"Try Body"<<endl; throw exception(); },
[](exception){ cout<<"Catch Body"<<endl; },
[]{ cout<<"Finally Body"<<endl; }
);
// You can even change values in this scope (notice the [&]?)
string what;
TryFinally(
[]{ throw exception(); },
[&](const exception &ex){ what = ex.what(); },
[]{}
);
cout<<what<<endl;
// What about custom exception types?
class test_exception_t : public std::exception{ public:
virtual const char *what() const noexcept{ return "My Test Exception"; }
};
TryFinally(
[]{ throw test_exception_t(); },
[](const exception &ex){ cout<<ex.what()<<endl; },
[]{}
);
// Can you tell the difference between two types of exceptions?
class second_exception_t : public std::exception{ public:
virtual const char *what() const noexcept{ return "My Second Test Exception"; }
string name;
};
TryFinally(
[]{ throw second_exception_t(); },
[](const exception &ex){
if(NULL == dynamic_cast<test_exception_t const *>(&ex))
cout<<"This is not the first kind of exception"<<endl;
if(NULL != dynamic_cast<second_exception_t const *>(&ex))
cout<<"This is the second kind of exception"<<endl;
},
[]{}
);
// What about exception types that aren't derived from std::exception?
TryFinally<const char *>(
[]{ throw "This is not even an exception!"; },
[](const char *ex){ cout<<ex<<endl; },
[]{}
);
// If you fail to catch the exception, the finally should still execute
try{
TryFinally(
[]{ throw "This is not even an exception!"; },
[](exception){ cout<<"This should not execute because we didn't catch the right type"<<endl; },
[]{ cout<<"Finally body still executes"<<endl; }
);
} catch(...){
cout<<"Exception escaped"<<endl;
}
// Let's do something more complex. I will modify and rethrow the exception
try{
TryFinally(
[]{ throw second_exception_t(); },
[](exception &ex){
// Let's give the exception a name and rethrow it
second_exception_t *s = dynamic_cast<second_exception_t *>(&ex);
s->name = "George";
// I don't even need to tell it what to throw
throw;
},
[]{ cout<<"Finally Body"<<endl; }
);
}
catch(const second_exception_t &ex){
cout<<"Exception named "<<ex.name<<endl;
}
return 0;
}
/*Copyright 2014 George Karagoulis
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.*/
/** A nifty try catch finally construction made possible by c++11's new lambda functions.
* It behaves just like you would want a try-catch-finally to behave, with a few minor
* querks. Firstly you can only catch one type of exception, the base type
* of all your exceptions, and if you want to know its type you dynamic cast its pointer.
*
* The default usage, which catches std::exception and has no code looks like this:
*
* TryFinally(
* []{}, // Try body
* [](const std::exception &){}, // Catch body
* []{}); // Finally body
*
* Note that the catch function should handle with a const reference, because it
* allows you to check which type the exception instance is.
*
* If you want to catch a custom exception type other than std::exception, call it "MyException",
* it looks like this:
*
* TryFinally<MyException>(
* []{}, // Try body
* [](const MyException &){}, // Catch body
* []{}); // Finally body
*
* \tparam EXCEPTION The type of exception which will be caught. If an exception is thrown that
* doesn't derive from this base type, the finally body will be executed but not the catch.
* \param _try The try body. This is executed first. Exceptions thrown here will be handled by the catch body.
* \param _catch The catch body. This is only executed if an exception was thrown inside the try block.
* It is required to take the handled exception class as an argument.
* \param _finally The finally body. This is executed regardless of whether an exception was thrown,
* either from the try body or the catch body.
*/
template<class EXCEPTION = std::exception, class TRY_BLOCK, class CATCH_BLOCK, class FINALLY_BLOCK>
inline void TryFinally(TRY_BLOCK _try, CATCH_BLOCK _catch, FINALLY_BLOCK _finally)
{
try
{
_try();
}
catch(EXCEPTION &e)
{
try
{
_catch(e);
}
catch(...)
{
_finally();
throw;
}
}
catch(...)
{
_finally();
throw;
}
_finally();
}
@karagog
Copy link
Author

karagog commented Sep 14, 2014

I have been studying the new c++ standard (c++11) and I was playing around with lambda functions today, and I came up with this implementation for try-catch-finally. Technically speaking, this was possible with the c++03 standard, but it would have been MUCH clunkier. The new lambda functions make this look actually quite sexy.

@karagog
Copy link
Author

karagog commented Sep 14, 2014

Note that you have to build this with the compiler flag: --std=c++0x

I just built it with g++ 4.8.1

@upperxcode
Copy link

Very good, I'll try to use

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment