CPP雜記——使用RAII機制管理實體資源

起初接觸到RAII機制是在使用std中的lock_guard()方法時對於其只需一行的加鎖方式感到好奇。
其實所謂RAII就是利用C++中構造的臨時對象一定會被析構的原理構造一個臨時對象,在構造時獲取需要納入管理的資源,並在其生命週期結束後隨析構函數的調用而釋放。

RAIIoperator=\color{red}{要注意的是,生成的RAII風格管理非實體類最好禁用拷貝構造函數和operator=}
(private=delete)\color{red}{(註冊爲private或=delete)}

編寫一個泛型RAII實體資源管理器?

大致構造(修改std::lock_gard)

先是大概的模板,對需要管理的資源分別在構建和析構時進行獲取和釋放,當然目前還有很多問題沒有得到處理

#include <type_traits>

template<typename ResourceType> 
class RAIIObj final {
public:
	using Res = ResourceType;

	explicit RAIIObj(Res& resource) : m_resource(resource) {
		m_resource.acquire();
	}
	~RAIIObj() {
		m_resource.release();
	}
	RAIIObj(const RAIIObj&)  = delete;
	RAIIObj(const RAIIObj&&) = delete;
	RAIIObj& operator=(const RAIIObj&)  = delete;
	RAIIObj& operator=(const RAIIObj&&) = delete;

private:
	Res&	m_resource;
};

在泛型化前隨便測試一下機制的正確性
在這裏插入圖片描述

泛化

RAII.hpp

#include <type_traits>
#include <functional>

template<typename ResourceType> 
class RAIIObj final {
public:
	using Res	  = ResourceType;
	using ObjType = RAIIObj<Res>;
	using AcqFun  = std::function<Res()>;
	using RelFun  = std::function<void(Res&)>;

	// 初始化,傳入生成/銷燬對象的方法來獲得/釋放資源
	RAIIObj(AcqFun acquire, RelFun release) noexcept :
		m_resource(acquire()),
		m_releaseFunc(release) {}
	// 直接使用resource+其釋放方法
	RAIIObj(Res& resource, RelFun release):
		m_resource(std::move(resource)),
		m_releaseFunc(std::move(release)) {}
	// resource+lambda
	RAIIObj(Res&& resource, RelFun&& release):
		m_resource(resource),
		m_releaseFunc(release) {}

	~RAIIObj() {
		if (m_flag) {
			m_simplified? m_resource.~Res(): m_releaseFunc(m_resource);
		}
	}
	// 拷貝構造函數
	RAIIObj(RAIIObj& obj) :
		m_resource(std::move(obj.m_resource)),
		m_releaseFunc(std::move(obj.m_releaseFunc)) {}
	// 移動構造函數
	RAIIObj(RAIIObj&& obj) :
		m_resource(obj.m_resource)),
		m_releaseFunc(obj.m_releaseFunc) {
		obj.m_flag = false;		//保留臨時對象中的數據
	}
	RAIIObj() {
		if (std::is_class<Res>::value) {
			m_resource = Res();
			m_simplified = true;
		}
		else {
			throw std::runtime_error("failed to allocate resource, need more arguments");
		}
	}


	// 獲取成員資源
	[[nodiscard]] inline 
		Res& get() noexcept { return m_resource; }
	[[nodiscard]] 
		Res& operator*() noexcept { return m_resource; }

	// 重載->操作符提供成員訪問代理
	// 此處用到了enable_if限定函數返回值
	// 即將classItem近似用作Resource類型的指針
	// 等價於typename<T, typename std::enabif<std::is...<>::value>::type
	template<typename Res = RAIIObj::Res>
	typename std::enable_if<std::is_pointer<Res>::value, Res>::type
	[[nodiscard]] operator->() noexcept { return m_resource; }

	template<typename Res = RAIIObj::Res>
	typename std::enable_if<std::is_class<Res>::value,   Res*>::type
	[[nodiscard]] operator->() noexcept {
		return std::addressof(m_resource);
	}

	ObjType& resetFlag(bool b = true) { m_flag = b; return *this; }

private:
	Res		m_resource;
	bool	m_flag		 = true;	//資源釋放標誌
	bool    m_simplified = false;
	RelFun	m_releaseFunc;
};

main.cpp

//#include "ASyncServer/ASyncServer.h"

#include <RAII.hpp>
#include <iostream>
class var {
public:
	var()  = default;
	~var() = default;
	static var  construct() {
		std::cout << "construct test" << std::endl;
		var	   temp;
		return temp;
	}
	static void destruct(var& item) {
		std::cout << "destruct test" << std::endl;
		item.~var();
	}
};

void TestFun() {
	RAIIObj<var> var1(var::construct, var::destruct);
	RAIIObj<var> var2(var1);
	std::cout << (void*)(&var1.get()) << std::endl;
}

int main(int argc, char* argv[]) {
	TestFun();
	return 0;
}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章