前述
golang的defer语法带来的便捷性和观感真是太好了,代码写起来神清气爽,c语言没有这个关键字有点可惜。
有许多相同想法的大佬已经模拟实现过了,这边拿其中一个写的不错的代码拿来再简单封装一下。
参考代码
封装实现和测试
#include <iostream>
#include <functional>
template <class F>
class final_act
{
public:
explicit final_act(F f) noexcept : f_(std::move(f)), invoke_(true) {}
final_act(final_act&& other) noexcept : f_(std::move(other.f_)), invoke_(other.invoke_)
{
other.invoke_ = false;
}
final_act(const final_act&) = delete;
final_act& operator=(const final_act&) = delete;
~final_act() noexcept
{
if (invoke_) f_();
}
private:
F f_;
bool invoke_;
};
template <class F>
inline final_act<F> finally(const F& f) noexcept
{
return final_act<F>(f);
}
template <class F>
inline final_act<F> finally(F&& f) noexcept
{
return final_act<F>(std::forward<F>(f));
}
// 以下对代码进行简单封装和测试
// 此种封装方式唯一不好的地方就是用了自增的计数器 宏生成的变量名比较丑陋 不过这些变量名也不需要关注就是了
#define COMBINE(x, y) x##y
#define COMBINE_TMP(x, y) COMBINE(x, y)
#define COMBINE_DIFF(x) COMBINE_TMP(x, __COUNTER__)
#define DEFER(func) auto COMBINE_DIFF(testdefer) = finally([&](){func;})
class ClassTest
{
public:
ClassTest() {
std::cout << "ClassTest constructor" << std::endl;
}
~ClassTest() {
std::cout << "ClassTest destructor" << std::endl;
}
};
void print() {
std::cout << "print" << std::endl;
}
void print(const std::string& s) {
std::cout << "print " << s << std::endl;
}
int main(int argc, char** argv) {
ClassTest *p = new ClassTest(); // #1
DEFER(delete p); // #2
DEFER(print()); // #3
DEFER(print("defer with macro")); // #4
std::string s1 = "defer without macro, using lambda";
std::string s2 = "defer without macro, using std::bind";
auto defer_without_macro_1 = finally([s1](){print(s1);}); // #5
auto defer_without_macro_2 = finally(std::bind((void(*)(const std::string&))print, s2)); // #6
final_act<void (*)()> original_usage(&print); // #7
std::cout << "main end" << std::endl; // #8
return 0;
}
得到的输出结果:
ClassTest constructor // #1
main end // #8
print // #7
print defer without macro, using std::bind // #6
print defer without macro, using lambda // #5
print defer with macro // #4
print // #3
ClassTest destructor // #2