Cpp Tricks Defer
- published
- reading time
- 2 minutes
One of my favorite uses for defer in Go is when a function has multiple return paths, but you still need to run the same handful of instructions before exiting. Instead of writing complicated logic to handle this, a simple defer goes a long way.
I have missed this functionality a lot in C++, but I’ve found a way to use destructors to accomplish the same. It’s not exactly the same as defer, but it’s a good workaround that brings some of the simplicity I appreciate from Go into my C++ code.
#include <functional>
#include <iostream>
class Defer
{
public:
explicit Defer(std::function<void()> func)
: func_(std::move(func))
, active_(true)
{}
~Defer() noexcept
{
if(active_)
func_();
}
void cancel()
{
active_ = false;
} // Optionally cancel the deferred action
private:
std::function<void()> func_;
bool active_;
};
// Helper function to simplify usage
template <typename F>
Defer defer(F&& func)
{
return Defer(std::forward<F>(func));
}
// Example 1: Simple deferred action
void example1()
{
std::cout << "Start of function" << std::endl;
auto cleanup = defer([] { std::cout << "Deferred action executed" << std::endl; });
std::cout << "End of function" << std::endl;
}
// Example 2: Updating the return value in the defer
int example2()
{
std::cout << "Allocating heap memory" << std::endl;
int myVal = 10;
defer([&myVal] {
myVal = 11;
std::cout << "Updated myVal on defer" << std::endl;
});
return myVal;
}
// Example 3: Demonstrating the cancel functionality
void example3()
{
std::cout << "Start of function with cancel" << std::endl;
auto cleanup = defer([] { std::cout << "Deferred action executed (should not run if canceled)" << std::endl; });
// Simulate a condition where the deferred action is not needed
bool condition = true;
if(condition)
{
std::cout << "Condition met, canceling deferred action" << std::endl;
cleanup.cancel(); // Cancel the deferred action
}
std::cout << "End of function with cancel" << std::endl;
}
int main()
{
std::cout << "Example 1\n-----------------------" << std::endl;
example1();
std::cout << "\nExample 2\n-----------------------" << std::endl;
int val = example2();
std::cout << "Example 2 returned " << val << std::endl;
std::cout << "\nExample 3\n-----------------------" << std::endl;
example3();
return 0;
}