C++ Defer 操作


C++ Defer

C++ 中並沒有官方的defer操作,所以需要自己實現一個。

跟一個guard函數類似,在一個棧對象的析構函數中調用defer函數,std::function 是一個不錯的選擇,可以bind一個已經存在的函數,也可以使用lambda表達式,所以第一個版本defer長這樣:

class Defer {
public:
    Defer(std::function<void()> defer): _defer(std::move(defer)) {}
    ~Defer() { _defer(); }
private:
    std::function<void()> _defer;
};

// 使用:
Defer defer1([]() { std::cout << "defer op" << std::endl;});

std::function<void()> func = []() { std::cout << "defer op" << std::endl;};
Defer defer2(func);

std::function很強大,但是代價也很高,在創建函數對象的時候總是會有 new操作的。雖然通常情況下影響不是很高,但是總覺得這是沒必要的。

下面是 GCC 中functional實現

private:
  static void
  _M_init_functor(_Any_data& __functor, _Functor&& __f, true_type)
  { ::new (__functor._M_access()) _Functor(std::move(__f)); }

  static void
  _M_init_functor(_Any_data& __functor, _Functor&& __f, false_type)
  { __functor._M_access<_Functor*>() = new _Functor(std::move(__f)); }

當然這個不是lambda表達式的問題,因為lambda表達式的創建是基本沒有開銷的,在C++中lambda表達式通常的實現是用一個仿函數來實現的。例如:

void func_call() {
   int var1 = xxx;
   std::string var2 = xxx;
   auto lambda = [var1, &var2]() mutable {
       // do something
   };
   lambda();
}

// 通常編譯器會處理為

void func_call() {
    struct func_call#lambda1 {
        func_call#lambda1(int v1,std::string& v2):_v1(v1),_v2(v2) {}
        operator ()() {
            // dosome thing
        }
    private:
        var1 _v1;
        var2 &_v2;
    }
    func_call#lambda1();
}

所以lambda表達式的構造和復制的開銷的非常低的。

我們基於這個思路來做第二版的defer操作:

template <class T>
class LambdaDefer {
public:
    LambdaDefer(T& closure) : _closure(closure) {}
    ~LambdaDefer() { _closure(); }

private:
    T& _closure;
};

// 使用:
auto deferop = [&]() { std::cout << "defer" << std::endl;};
LambdaDefer<decltype(deferop)> defer(deferop);

性能測試在這里:https://quick-bench.com/q/4IKpxAA5VEbXVziV1G2Po-ZupSE

性能表現符合預期,但是使用起來太麻煩了。

因為想要構建一個LambdaDefer,必須要顯示的指定模板類型,C++11大致是止步於此了。

不過 C++17 就有更好的實現方式了,因為有類型推導這個神奇的操作:

// c++ 11
auto pair = std::make_pair<int, double>(1, 1.2);
// c++ 17
auto pair = std::make_pair(1, 1.2);

按照這個思路我們可以這樣搞:

template <class T>
class Defer {
public:
	Defer(T& closure) : _closure(closure) {}
	Defer(T&& closure) : _closure(std::move(closure)) {}
	~Defer() { _closure(); }
private:
	T _closure;
};

// only C++17 support
auto deferop = []() { std::cout << "defer" << std::endl; };
Defer defer {deferop};
Defer defer2 {[]() { std::cout << "defer" << std::endl; }};


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM