3 ms·
I'd like "defer_func" to be an option; I do have some code that seriously uses it that way. But all in all defer defaulting to scope would be a lot more useful.
by jerf 6y ago
I'd like "defer_func" to be an option; I do have some code that seriously uses it that way. But all in all defer defaulting to scope would be a lot more useful.
I've written some functions-in-functions solely to get "scope-like" deferral. Now, so far, none of them have ever survived refactoring, in that they've always been lifted up to become their own top-level functions where defer resumes working like I wanted anyhow. But I've also got a ton of code where the difference doesn't much matter (a function with only one scope, or where defer is only on the outer-most scope anyhow), and it still seems like scope would be a better default.
- knorker 6y agoI'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.