5 ms·
This is one of my favorite features of unique_ptr. It is an all-purpose way to make something happen at the end of scope without having to write a new struct an
by thrownaway2424 10y ago
This is one of my favorite features of unique_ptr. It is an all-purpose way to make something happen at the end of scope without having to write a new struct and destructor. You don't even need the pointer at all since you can simply do:
std::unique_ptr<void> finally(42, [](void* unused){ whatever });
- toth 10y agoThat is a pretty cool use. In practice though, it is pretty unreadable unless you wrap it in a macro or template, and if you are doing that you might as well just implement it yourself. Something like: struct OnScopeExit { OnScopeExit(std::function<void()> f) : f_(f) {}; ~OnScopeExit() { f_();}; std::function<void()> f_; }; Which you'd then use as { OnScopeExit x([]() { std::cout << "Exited scope!" << std:endl; }; // ... }
- joebaf 10y agothat's the beauty of using destructors to clean things when an object goes out of scope. in your OnScopeExit we could use templates (and not use std::function), that way any callable thing could be called - and it would be lighter than std::function
- toth 10y agoI actually don't think there's a nice way of doing this without making the interface slightly more annoying. If you make OnScopeExit a template on a callable, then you need to give it the type of the callable explicitly on construction, which means that using a lambda becomes more annoying. I.e., you'd have to do it like this: auto f = []() { std::cout << "Exited Scope!" << std::endl; }; OnScopeExit<decltype(f)> x(f); The way unique_ptr does it is by using type erasure, which requires a virtual function call internally, just like std::function.
- Kristine1975 10y ago>The way unique_ptr does it is by using type erasure, which requires a virtual function call internally That's shared_ptr. unique_ptr does not perform type erasure.
- deleted 10y ago[deleted]
- bennofs 10y agoCouldn't you do something like `auto x = make_on_scope_exit([]() { ... });`?
- toth 10y agoYes, you are right, I am wrong! That works just fine. For the record: template<typename T> struct OnScopeExit { OnScopeExit(T f) : f_(f) {}; ~OnScopeExit() { f_();}; T f_; }; template<typename T> OnScopeExit<T> make_scope_exit(T f) { return OnScopeExit<T>(f); } And then you use it as auto x = make_scope_exit([]() { std::cout << "Exitced Scope!" << std::endl; });
- corysama 10y agoAlexandrescu at CPPCon2015 describes how he does ScopeExit starting at 18 minutes into this video http://youtu.be/WjTrfoiB0MQ http://youtu.be/WjTrfoiB0MQ
- kzhahou 10y agoWith all due respect to Alexandrescu's incredible C++ skills, I find that his style of programming is very detrimental to the overall quality of the C++ environment. C++ is a very abusable language. This is reflected both in its capabilities and in the ability to shoot yourself in the foot. These points are obviously well-covered in any C++ discussion. Now, Alexandrescu brings a style of programming in which you exploit templates, sometimes macros, operator overloading, and everything else, in order to squeeze out more generality/reusability out of a piece of code, or simplify the coder-visible syntax of some construct. We see that right here: the above comments show a few ways to run arbitrary code on a scope exit. Each of the examples above is perfectly easy to follow along. But then the YouTube video show's Alexandrescu's take, and it's a real brain-warper. He invokes a couple of levels of C++ trickery to get his effect. Now, his end result is wonderful... but it's also not easily understandable. If you write code in his style at your job, good luck to the person that takes over your code after you leave the project. They'll have a hell of a time. IMHO a developer should always sacrifice syntactic sugar, with no performance penalty if done correctly, in exchange for more understandable code.
- thrownaway2424 10y agoYou're right but I am just that lazy sometimes.
- toth 10y agoLazyness is a great virtue! Thanks for the suggestion on unique_ptr , it should be pretty useful for debugging!
- leetNightshade 10y agoAnother name for this style of wrapper, with some extra functionality, is known as a Scope Guard. Wiki page: https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Scope_Guard https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Scope_Guar... Clean implementation: http://stackoverflow.com/a/28413370 http://stackoverflow.com/a/28413370
- mavam 10y agoI understand that your point is that unique_ptr facilitates resource management. But the example you provide is a misleading. How is this supposed to compile? The deleter type is part of the unique_ptr. So you need something along these lines: auto scope_guard = [](void*) { }; unique_ptr<void, decltype(scope_guard)> finally{nullptr, scope_guard}; This is not very idiomatic. Something like toth mentioned makes more sense. If you want it to be efficient, use this: template <class Fun> class scope_guard { scope_guard() = delete; scope_guard(const scope_guard&) = delete; scope_guard& operator=(const scope_guard&) = delete; public: scope_guard(Fun f) : fun_(std::move(f)) {} ~scope_guard() { fun_(); } private: Fun fun_; }; template <class Fun> scope_guard<Fun> make_scope_guard(Fun f) { return {std::move(f)}; } auto guard = make_scope_guard([] { cleanup(); }); The difference is: there's no indirection through std::function, so you save yourself a (potential) heap allocation.
- thrownaway2424 10y agoYeah, again I am lazy and did not want to do all that typing on my phone. See https://godbolt.org/g/ywU2en https://godbolt.org/g/ywU2en for the full monty.
- Kristine1975 10y agoFacebook's Folly library implements something similar: https://github.com/facebook/folly/blob/master/folly/ScopeGuard.h https://github.com/facebook/folly/blob/master/folly/ScopeGua... It provides some macros to make it easier to use, e.g. SCOPE_EXIT { cleanup(); more_cleanup(); if (needs_even_more_cleanup) even_more_cleanup(); };
- leetNightshade 10y agoIt sounds to me what you're trying to do is essentially what a Scope Guard is for. Here's a wiki on them: https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Scope_Guard https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Scope_Guar... And here's a nice and clean implementation of one I've used recently: http://stackoverflow.com/a/28413370 http://stackoverflow.com/a/28413370