Modern C++的應用,實現golang中的defer

modern C++實現 golang 的defer

關於RAII的一些思考。

defer 的簡介

注:沒有 golang 語法基礎的讀者可以看看,反之,可以跳過。

golang語法中的defer是什麼?

defer用來聲明一個延遲函數,把這個函數放入到一個棧上, 當外部的包含方法return之前,返回參數到調用方法之前調用,也可以說是最外層方法體執行結束時調用。

舉一個簡單的例子,在函數test()中用defer聲明在函數結束後執行打印Exit function -> test()

package main
import "fmt"

func test() {
    defer fmt.Println("Exit function -> test()")
    fmt.Println("Enter function -> test()")
}

func main() {
    test()
}

執行結果:

Enter function -> test()
Exit function -> test()

涉及 modern C++ 語法簡介

auto

C++11標準之前的是auto含義的分割線,之前的auto沒有什麼實際的含義,僅僅代表除了static之外的存儲屬性。之後的auto用於編譯器自動推導變量類型,用auto初始化的變量編譯器會自動推導其類型。

需要注意的是:

  • auto定義變量的時候沒有缺省值。下面這樣的代碼就會報錯:

    auto value;
    
  • auto定義的變量第一次推導出變量的類型就不會在自動更改,比如下面這樣的代碼編譯器就會有警告:

    auto value = 10;
    value = 1.2; // Warning: implicit conversion from 'double' to 'int' 
    			 // changes value from 1.2 to 1
    

幾個小例子:

注:讀者感興趣的話,請自行在MSVC編譯器下編譯,因爲MSVC編譯出的這段代碼可視性能好一點。博主剛把MSVC卸載了,暫時也沒有windows下的C/C++編譯環境。

#include <iostream>
#include <typeinfo>

// 讀者先不必理會這是個什麼東西,這個只是用來打印分割線的
auto divider = [] {
    for(auto i = 0; i < 10; ++i) std::cout << '--';
    std::cout << std::endl;
}

int main() { 
	auto value_1 = 10;
    std::cout << "value_1: " << value_1 << std::endl;
    std::cout << "value_1 type is: " << typeid(value_1).name() << std::endl;
    divider();
	auto value_2 = 1.2;
    std::cout << "value_2: " << value_2 << std::endl;
    std::cout << "value_2 type is: " << typeid(value_2).name() << std::endl;
    divider();
	auto value_3 = &value_1;
    std::cout << "value_3: " << value_3 << std::endl;
    std::cout << "value_3 type is: " << typeid(value_3).name() << std::endl;
    return 0;
}

lambda

詳細用法和介紹可以看看這個:c++中的可調用對象

博主這裏的代碼採用MSVC編譯器編譯,因爲它編譯出的 typeid(value).name() 比g++的可視性更好一些。

lambda 用來定義一個可調用對象,也可以說是匿名函數。

#include <iostream>
#include <string>
// 注:MSVC編譯器可以不用包含typeinfo,g++編譯器必須包含才能使用typeid
// #include <typeinfo>  

// 定義一個匿名函數對象賦值給 func_args
auto func_args = [](const std::string& s) {
    std::cout << s << std::endl;
}

// 定義一個匿名函數對象賦值給 func_non_args
auto func_non_args = [] {
    std::cout << "call func_non_args..." << std::endl;
}

int main() {
    std::cout << "func_args type is: " << typeid(func_args).name() << std::endl;
    func_args("call func_args...");
    std::cout << "func_args type is: " << typeid(func_non_args).name() << std::endl;
    func_non_args();
    return 0;
}

執行結果:

func_args type is: class <lambda_5f1310fc7b149b7657eb13239ade2207>
call func_args...
func_non_args type is: class <lambda_690afd7bca8dc2199fda46c38926a422>
call func_non_args...

右值引用

//TODO

std::move

//TODO

std::foraward

//TODO

具體實現

預覽

我想要實現的最終效果:

#include <iostream>

func test() {
    // DEFER 換成小寫也可以
    DEFER { std::cout << "Exit function -> test()" << std::endl; };
    std::cout << "Enter function -> test()" << std::endl;
}

int main() {
    test();
}

執行結果:

Enter function -> test()
Exit function -> test()

設計過程

//TODO

最終結果

#include <iostream>

template <typename T>
class _Defer {
  public:
    _Defer(T&& d) : _d(std::move(d)){}  // 移動語義
    ~_Defer() { _d(); }
  private:
    T _d;
};

class Defer {
  public:
    template <typename T>
    _Defer<T> operator+(T&& d) {
      return _Defer<T>(std::forward<T>(d));  // 完美轉發
    }
};

#define CONCAT_IMPL(prefix, suffix) prefix##suffix  //宏連接
#define CONCAT(perfix, suffix) CONCAT_IMPL(prefix, suffix)
#define UNIQUE_NAME(prefix) CONCAT(prefix, __COUNTER__)
#define DEFER auto UNIQUE_NAME(defer_) = Defer() + [&] //lambda表達式

void test() {
  // 在test()函數推出後打印 “func exit!”
  DEFER { std::cout << "func exit!" << std::endl;  };
}

int main(){
  std::cout << "Call test() function..." << std::endl;
  test();
  return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章