C++ 学习笔记(13)RAII 模板化 和 ScopeFuard 模板化

巧妙运用 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 ;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值