起初接触到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;
}