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