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;
}