2 ms·
I've written this a few times: class defer{public:defer(std::function<()> f):f_(std::move(f)){} ~defer(){f_();}private:std::function f_;}; Then fd =
by knorker 6y ago
I've written this a few times:
class defer{public:defer(std::function<()> f):f_(std::move(f)){} ~defer(){f_();}private:std::function f_;};
Then
fd = socket(…);
defer _([]{close(fd);});
But yeah, most of the time a refactor will instead create a proper wrapper class. It's rare that I want to RAII something, but only in some cases. E.g. I probably want RAII on FDs always, with proper ownership, not merely in some cases.
And this is also what Go missed. I'm a big fan of RAII.
- gpderetta 6y agoNo need to box with std::function. Since C++17 this is enough: template<class Fn> struct defer { Fn fn; ~defer() { fn(); } }; template<class Fn> defer(Fn) -> defer<Fn>; int main() { defer _ { [] { std::cout << "exit"; }}; } Although you might want to add the ability to dismiss() the guard. edit: a more complete implementation: https://godbolt.org/z/6675K1 https://godbolt.org/z/6675K1 . I like to name my guards. Making them anonymous is left as an exercise for the reader.
- knorker 6y agoYeah, I chose not to templatize and add dismiss() mostly to make it fit better in a comment. But like I said at some point, if it gets complicated, then probably the value should be properly wrapped, with actual owner semantics rather than defers.
- gpderetta 6y agoYou are right in most cases. I find it useful for transactional code though, where I might be modifying a bunch of data structures and I want to undo everything on error. Doesn't really make much sense to write classes in this case if the code is really function specific.