巧妙运用 std::function<> 和 lambda 表达式,做到泛化
PS: 手动清理在异常安全和资源安全方面的缺点:手动调的一个坏处是,如果在资源申请和释放之间发生了异常,那么释放将不会发生,此外,手动释放需要在函数的所有出口处都去调释放函数,万一某天有人修改了代码,加了一处return,而在return之前忘了调释放函数,资源就泄露了。
RAII 模板
#include <bits/stdc++.h>
#define rep( i , j , n ) for ( int i = int(j) ; i < int(n) ; ++i )
#define dew( i , j , n ) for ( int i = int(n-1) ; i > int(j) ; --i )
#define _PATH __FILE__ , __LINE__
typedef std::pair < int , int > P ;
using std::cin ;
using std::cout ;
using std::endl ;
using std::string ;
namespace YHL {
// RAII 类, 管理 dismissed 变量和释放资源的函数 myRealease
class RAII final {
private:
using funType = std::function<void()> ;
funType myRelease ;
// dismissed 结合的是 ScopeGuard
mutable bool dismissed ;
public:
explicit RAII(funType _myRelease, funType myAcquire=[]{}) noexcept
: myRelease(_myRelease)
, dismissed(false) {
// RAII 构造时获取资源
myAcquire() ;
}
~RAII () noexcept {
// RAII 析构时释放资源, myRelease 函数有时只能调用一次
if ( dismissed == false ) {
myRelease() , dismissed = true ;
}
}
RAII (RAII&& other)
: myRelease(other.myRelease), dismissed(other.dismissed) {
// 转移释放资源的权利
other.Dismiss(true) ;
}
// 改变“是否执行撤销操作”
void Dismiss (const bool _dismissed) noexcept {
dismissed = _dismissed ;
}
// 不可复制, 不可赋值
RAII(const RAII&) = delete ;
RAII& operator=(const RAII&) = delete ;
} ;
template<typename T>
inline T* allocate(T *target) {
assert(target == nullptr) ;
target = new T ;
cout << "成功分配资源! " << endl ;
return target ;
}
template<typename T>
inline void destroy(T *target) {
assert(target not_eq nullptr) ;
delete target ;
target = nullptr ;
cout << "成功释放资源!" << endl ;
}
}
void function1() {
cout << "\n测试 RAII 在文件中的操作\n" ;
std::ofstream Out("RAII(3).txt") ;
Out << "I will go with you in the rest of my life.\n" ;
if ( true ) {
// 出了作用域,(ON_SCOPE_EXIT)就会析构
YHL::RAII admin([&Out]() {
if ( Out.is_open() ) Out.close() ;
}) ;
}
if ( Out.is_open() == false )
cout << "文件关闭成功!\n" ;
}
void function2() {
cout << "\n测试 RAII 在线程互斥锁中的操作\n" ;
auto cnt = 0 ;
std::mutex myMutex ;
constexpr int N = 1e4 ;
constexpr int size = 5 ;
std::array<std::thread, size> threads ;
rep ( i , 0 , size ) {
threads[i] = std::thread([&cnt, &myMutex](){
rep ( i , 0 , N ) {
YHL::RAII RAIILock([&myMutex](){ myMutex.unlock() ;}, [&myMutex](){ myMutex.lock() ;}) ;
++cnt ;
}
}) ;
}
// join 操作同样可以设置 RAII 操作, 嵌套 lambda
rep ( i , 0 , size ) threads[i].join() ;
cout << "结果 cnt : " << cnt << endl ;
assert(cnt == N * size) ;
}
void function3() {
cout << "\n测试 RAII 在内存分配中的操作\n" ;
void *ptr = nullptr ;
if ( true ) {
YHL::RAII mallocRAII([&ptr](){
assert(ptr not_eq nullptr) ;
std::free(ptr) ;
ptr = nullptr ;
cout << "成功释放资源!" << endl ;
}, [&ptr](){
ptr = std::malloc(1024) ;
cout << "成功分配资源 : " << _msize(ptr) << " 字节" << endl ;
}) ;
}
assert(ptr == nullptr) ;
if ( true ) {
YHL::RAII newRAII([&ptr](){
YHL::destroy(static_cast<int*>(ptr)) ; ptr = nullptr ;
}, [&ptr](){
ptr = YHL::allocate(static_cast<int*>(ptr)) ;
}) ;
}
assert(ptr == nullptr) ;
}
void function4() {
cout << "\n测试 ScopeGuard 的操作\n" ;
std::vector<int> array ;
constexpr int N = 10 ;
if ( true ) {
YHL::RAII example([&array](){
// 跳出 if 本应该清空 array 的
array.clear() ; array.shrink_to_fit() ;
}, [&array](){
rep ( i , 0 , N )
array.emplace_back(i + 1) ;
}) ;
// 撤销动作, 不清空
example.Dismiss(true) ;
}
for ( const auto &it : array )
cout << it << " " ;
cout << endl ;
// 如果中途发生异常, 就不会执行 Dismiss, array 不会清空;
// 正常情况下会执行 Dismiss
}
int main () {
function1() ;
function2() ;
function3() ;
function4() ;
return 0 ;
}
ScopeGuard 模板:
#include <bits/stdc++.h>
#define rep( i , j , n ) for ( int i = int(j) ; i < int(n) ; ++i )
#define dew( i , j , n ) for ( int i = int(n-1) ; i > int(j) ; --i )
#define _PATH __FILE__ , __LINE__
typedef std::pair < int , int > P ;
using std::cin ;
using std::cout ;
using std::endl ;
using std::string ;
namespace YHL {
class ScopeGuard {
using funType = std::function<void()> ;
private:
funType onExitScope ;
mutable bool dismissed ;
public:
explicit ScopeGuard(funType _onExitScope, funType acquire = []{})
: onExitScope(_onExitScope), dismissed(false)
{ acquire() ; }
~ScopeGuard() throw() {
if ( dismissed == false )
onExitScope() , dismissed = true ;
}
void Dismiss(const bool _dismissed) const throw() {
dismissed = _dismissed ;
}
private:
ScopeGuard(const ScopeGuard&) = delete ;
ScopeGuard& operator=(const ScopeGuard&) = delete ;
} ;
// 宏定义控制 ON_SCOPE_EXIT 命名
#define SCOPEGUARD_LINENAME_CAT(name, line) name##line
#define SCOPEGUARD_LINENAME(name, line) SCOPEGUARD_LINENAME_CAT(name, line)
#define ON_SCOPE_EXIT(callback) YHL::ScopeGuard SCOPEGUARD_LINENAME(EXIT, __LINE__)(callback)
#define ON_SCOPE_EXIT2(callback, acquire) YHL::ScopeGuard SCOPEGUARD_LINENAME(EXIT, __LINE__)(callback, acquire)
}
int main() {
std::ofstream out("RAII(6).txt") ;
out << "In the rest of my life\n" ;
ON_SCOPE_EXIT([&]{
out.close() ; cout << "文件已关闭\n" ;
}) ;
std::vector<int> array ;
rep( i , 0 , 10 ) array.emplace_back(i + 1) ;
if ( true ) ON_SCOPE_EXIT([&]{
array.clear() ; array.shrink_to_fit() ;
cout << "清理 vector\n" ;
}) ;
// main 结束后 array 是空的
for ( const auto &it : array ) cout << it << " " ; cout << endl ;
if ( true ) ON_SCOPE_EXIT2([&]{
array.pop_back() ;
}, [&]{
rep( i , 0 , 5 ) array.emplace_back(i << 1) ;
for ( const auto &it : array ) cout << it << " " ; cout << endl ;
}) ;
for ( const auto &it : array ) cout << it << " " ; cout << endl ;
return 0 ;
}