Last active
September 25, 2017 13:05
-
-
Save yisonPylkita/9f49720a1729b5841981439f709396a4 to your computer and use it in GitHub Desktop.
Execute code on scope leave
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// @file on_scope_leave.hpp | |
/// @brief Sane way to handle C-style cleanups in C++ | |
/// @author Wojciech Bartnik <yisonPylkita@gmail.com | |
/// | |
/// Lets assume you have C-style function `int open_port(const char *port_name)` | |
/// and this function returns a file descriptor to opened device port. | |
/// Normally you would need to write code like this | |
/// | |
/// int port_fd = open_port("/dev/ttyUSB0"); | |
/// try { | |
/// // here port_fd is beeing used | |
/// } catch (const std::exception &ex) { | |
/// close(port_fd); | |
/// throw ex; | |
/// } catch (...) { | |
/// close(port_fd); | |
/// throw "Somethig bad happend here"; | |
/// } | |
/// close(port_fd); | |
/// | |
/// Because of C++ exceptions you have to: | |
/// 1) catch all exceptions | |
/// 2) close file descriptor opened by open_port() | |
/// 3) retrow exception | |
/// | |
/// This approach has two major some drawbacks: | |
/// 1) Things are getting more commplicated with every another file descriptor you need to close | |
/// 2) You are loosing informations about exception type (or you need to | |
/// write catch'es for all possible exceptions to rethrow them with the same type) | |
/// | |
/// Fear not, here is the savior ^^ | |
/// | |
/// Just call | |
/// | |
/// #include "on_scope_leave.hpp" | |
/// | |
/// on_scope_leave([port_fd] { | |
/// close(port_fd); | |
/// }); | |
/// | |
/// and the job is done. | |
/// If you want to capture multiple variables you need to wrap whole lambda in parentheses: | |
/// | |
/// on_scope_leave(([port_fd, &logger] { | |
/// close(port_fd); | |
/// logger->warn("I am leaving the scope"); | |
/// })); | |
/// | |
/// Yet this solution is not a silver bullet. It has one drawback - you have to be certain | |
/// that lambda provided by you NEVER throws an exception. Oherwise your application will be | |
/// terminated by kernel. | |
#pragma once | |
#include <functional> | |
#define TOKENPASTE(x, y) x ## y | |
#define TOKENPASTE2(x, y) TOKENPASTE(x, y) | |
#define UNIQUE TOKENPASTE2(Unique_, __LINE__) | |
namespace on_scope_leave_impl { | |
/// Execute some code on scope leave | |
class on_scope_leave_class { | |
public: | |
using callback = std::function<void()>; | |
on_scope_leave_class(const callback &on_destroy) { | |
_on_destroy = on_destroy; | |
} | |
// Disallow object move or copy | |
on_scope_leave_class(const on_scope_leave_class &) = delete; | |
on_scope_leave_class operator=(const on_scope_leave_class &) = delete; | |
on_scope_leave_class(on_scope_leave_class &&) = delete; | |
on_scope_leave_class operator=(on_scope_leave_class &&) = delete; | |
~on_scope_leave_class() { | |
_on_destroy(); | |
} | |
private: | |
callback _on_destroy; | |
}; | |
#define on_scope_leave(callback) on_scope_leave_impl::on_scope_leave_class UNIQUE(callback) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment