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