c++模拟实现defer

 

前述

golang的defer语法带来的便捷性和观感真是太好了,代码写起来神清气爽,c语言没有这个关键字有点可惜。

有许多相同想法的大佬已经模拟实现过了,这边拿其中一个写的不错的代码拿来再简单封装一下。

参考代码

https://github.com/Microsoft/GSL/blob/ebe7ebfd855a95eb93783164ffb342dbd85cbc27/include/gsl/gsl_util#L85-L89

封装实现和测试

#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