C++ Boost ScopeExit超详细讲解
作者:无水先生
一、提要
资源有很多种,每种都封装一套,还是挺繁琐的!对于比较少使用或者一个程序很可能只会用一次的资源,我们不想封装,在这种情况下用Boost.ScopeExit。
二、退出作用域(Boost.ScopeExit)
库 Boost.ScopeExit 使得在没有资源特定类的情况下使用 RAII 成为可能。
2.1 范例1.UsingBOOST_SCOPE_EXIT
#include <boost/scope_exit.hpp> #include <iostream> int *foo() { int *i = new int{10}; BOOST_SCOPE_EXIT(&i) { delete i; i = 0; } BOOST_SCOPE_EXIT_END std::cout << *i << '\n'; return i; } int main() { int *j = foo(); std::cout << j << '\n'; }
计算结果:
Boost.ScopeExit 提供了宏 BOOST_SCOPE_EXIT,它可以用来定义一些看起来像本地函数但没有名字的东西。但是,它确实有一个括号中的参数列表和大括号中的块。 必须包含头文件 boost/scoped_exit.hpp 才能使用 BOOST_SCOPE_EXIT。
宏的参数列表包含来自外部范围的变量,这些变量应该可以在块中访问。变量通过副本传递。要通过引用传递变量,它必须以 & 符号作为前缀,如示例2.1 范例1. 中所示。
如果变量在参数列表中,则块中的代码只能从外部范围访问变量。
BOOST_SCOPE_EXIT 用于定义一个块,该块将在定义块的范围结束时执行。在示例 3.1 中,使用 BOOST_SCOPE_EXIT 定义的块在 foo() 返回之前执行。
BOOST_SCOPE_EXIT 可用于从 RAII 中受益,而无需使用特定于资源的类。 foo() 使用 new 创建一个 int 变量。为了释放变量,使用 BOOST_SCOPE_EXIT 定义了一个调用 delete 的块。即使函数由于异常而提前返回,也保证执行此块。在示例 1 中,BOOST_SCOPE_EXIT 与智能指针一样好。
请注意,变量 i 在 BOOST_SCOPE_EXIT 定义的块末尾设置为 0。然后 i 由 foo() 返回并写入 main() 中的标准输出流。但是,该示例不显示 0。j 设置为随机值 - 即 int 变量在内存被释放之前所在的地址。 BOOST_SCOPE_EXIT 后面的块获得了对 i 的引用并释放了内存。但由于该块是在 foo() 的末尾执行的,因此将 0 分配给 i 为时已晚。 foo() 的返回值是在 i 设置为 0 之前创建的 i 的副本。
如果您使用 C++11 开发环境,则可以忽略 Boost.ScopeExit。在这种情况下,您可以在 lambda 函数的帮助下使用没有资源特定类的 RAII。
2.2 示例2.Boost.ScopeExit和C++11的lambda函数
#include <iostream> #include <utility> template <typename T> struct scope_exit { scope_exit(T &&t) : t_{std::move(t)} {} ~scope_exit() { t_(); } T t_; }; template <typename T> scope_exit<T> make_scope_exit(T &&t) { return scope_exit<T>{ std::move(t)}; } int *foo() { int *i = new int{10}; auto cleanup = make_scope_exit([&i]() mutable { delete i; i = 0; }); std::cout << *i << '\n'; return i; } int main() { int *j = foo(); std::cout << j << '\n'; }
运算结果:
示例2 定义了类 scope_exit,其构造函数接受一个函数。该函数由析构函数调用。此外,还定义了一个辅助函数 make_scope_exit(),它可以在无需指定模板参数的情况下实例化 scope_exit。
在 foo() 中,一个 lambda 函数被传递给 make_scope_exit()。 lambda 函数看起来像示例 3.1 中 BOOST_SCOPE_EXIT 之后的块:地址存储在 i 中的动态分配的 int 变量通过删除被释放。然后将 0 分配给 i。
该示例与前一个示例执行相同的操作。不仅 int 变量被删除,而且 j 在写入标准输出流时也没有设置为 0。
2.3 示例3.特点BOOST_SCOPE_EXIT
#include <boost/scope_exit.hpp> #include <iostream> struct x { int i; void foo() { i = 10; BOOST_SCOPE_EXIT(void) { std::cout << "last\n"; } BOOST_SCOPE_EXIT_END BOOST_SCOPE_EXIT(this_) { this_->i = 20; std::cout << "first\n"; } BOOST_SCOPE_EXIT_END } }; int main() { x obj; obj.foo(); std::cout << obj.i << '\n'; }
示例介绍了 BOOST_SCOPE_EXIT 的一些特性:
- 当 BOOST_SCOPE_EXIT 用于在一个范围内定义多个块时,这些块以相反的顺序执行。示例 3 先显示后显示。
- 如果没有变量将传递给 BOOST_SCOPE_EXIT,则需要指定 void。括号不能为空。
- 如果您在成员函数中使用 BOOST_SCOPE_EXIT 并且需要传递指向当前对象的指针,则必须使用 this_ 而不是 this。
示例3:显示first,last
, 和20
in that order.
三、练习
BOOST_SCOPE_EXIT(&flag) { } BOOST_SCOPE_EXIT_END
BOOST_SCOPE_EXIT和 BOOST_SCOPE_EXIT_END都是配合着使用的, BOOST_SCOPE_EXIT()里面可以传入多个参数。其作用相当于回调函数,
在作用域结束之后程序会自动调用 BOOST_SCOPE_EXIT到 BOOST_SCOPE_EXIT_END之间的代码。
包含的头文件是 #include <boost/scope_exit.hpp>
下面是一个简单的例子:
#include <boost/scope_exit.hpp> void PrintCout(const std::string& str) { bool submitted = false; BOOST_SCOPE_EXIT(&submitted ) { if (!submitted) std::cout<<"false"<<std::endl; else std::cout<<"true"<<std::endl; } BOOST_SCOPE_EXIT_END submitted = ((str == "Y")? true:false); } int main(int argc, char* argv[]) { std::string str; std::cin>>str; while(str != "q"){ PrintCout(str); std::cin>>str; } }
这里的 BOOST_SCOPE_EXIT()可以传入多个参数,格式:
BOOST_SCOPE_EXIT(¶meter1,¶meter2,...)
到此这篇关于C++ Boost ScopeExit超详细讲解的文章就介绍到这了,更多相关C++ Boost ScopeExit内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!