1.什么是RAII?
RAII(Resource Acquisition Is Initialization)機制是Bjarne Stroustrup首先提出的,也稱直譯為“資源獲取就是初始化”,是C++語言的一種管理資源、避免泄漏的機制。
C++標準保證任何情況下,已構造的對象最終會銷毀,即它的析構函數最終會被調用。
RAII 機制就是利用了C++的上述特性,在需要獲取使用資源RES的時候,構造一個臨時對象(T),在其構造T時獲取資源,在T生命期控制對RES的訪問使之始終保持有效,最后在T析構的時候釋放資源。以達到安全管理資源對象,避免資源泄漏的目的。
2.為什么要使用RAII?
那么我們經常所說的資源是如何定義的?說到資源,我們立刻能想到的就是內存啊,文件句柄等等啊,但只有這些嗎?
對于資源的概念不要想象的太狹隘,在計算機系統中,資源是個定義寬泛的概念,所有數量有限且對系統正常運行具有一定作用的元素都是資源。比如:網絡套接字、互斥鎖、文件句柄、內存、數據庫記錄等等,它們屬于系統資源。由于系統的資源是有限的,就好比自然界的石油,鐵礦一樣,不是取之不盡,用之不竭的。
所以,我們在編程使用系統資源時,都必須遵循一個步驟:
1.申請資源;
2.使用資源;
3.釋放資源。
第一步和第三步缺一不可,因為資源必須要申請才能使用的,使用完成以后,必須要釋放,如果不釋放的話,就會造成資源泄漏。
3.實戰應用
3.1一個簡單的例子:指針申請空間,釋放空間
void Func()
{
int *ip =
new int[
10];
delete[] ip;
}
使用RAII技術后:
template<
class PointerType>
class My_Pointer
{
public: My_Pointer(PointerType* _ptr, size_t sz) { _ptr =
new PointerType[sz]; m_ptr = _ptr; } ~My_Pointer() {
delete []m_ptr; }
protected: PointerType m_ptr;
}
3.2 scope lock (局部鎖技術)
在很多時候,為了實現多線程之間的數據同步,我們會使用到 mutex,critical section,event,singal 等技術。但在使用過程中,由于各種原因,有時候,我們會遇到一個問題:由于忘記釋放(Unlock)鎖,產生死鎖現象。
采用RAII 就可以很好的解決這個問題,使用著不必擔心釋放鎖的問題. 示例代碼如下:
My_scope_lock 為實現 局部鎖的模板類.
LockType 抽象代表具體的鎖類 .如基于 mutex 實現 mutex_lock 類
template<
class LockType>
class My_scope_lock
{
public: My_scope_lock(LockType& _lock):m_lock(_lock) { m_lock.occupy(); } ~My_scope_lock() { m_lock.relase(); }
protected: LockType m_lock;
}
使用的時候:
int counter =
0;
void routine();
mutex_lock m_mutex_lock;
void routine()
{ My_scope_lock l_lock(m_mutex_lock); counter++;
}
我們可以根據上面的例子類推出好多這樣例子。如讀寫文件的時候很容易忘記關閉文件,如果借用 RAII技術,就可以規避這種錯誤。再如對數據庫的訪問,忘記斷開數據庫連接等等都可以借助RAII 技術也解決。
4.RAII模板化實現
按照上節的做法,如果你有很多個資源對象要用RAII方式管理,按這個辦法就要為每個類寫一個RAII類。
想到這里,我瞬間覺得好煩燥,都是類似的代碼,卻要一遍一遍的重復,就不能有個通用的方法讓我少寫點代碼嘛!!!
于是我利用C++11的新特性(類型推導、右值引用、移動語義、類型萃取、function/bind、lambda表達式等等)寫了一個通用化的RAII機制,滿足各種類型資源的管理需求。
#include "Wishbone/Foundation.h"
#include <type_traits>
#include <functional>namespace Wishbone
{
template<
typename T>
struct no_const{
using type =
typename std::conditional<
std::is_const<T>::value,
typename std::remove_const<T>::type, T>::type;};
class RAII{
public:
typedef std::function<
void()> FunctionType;
explicit RAII(FunctionType release, FunctionType acquire = [] {},
bool default_com =
true)
noexcept :_commit(default_com),_release(release){acquire();}~RAII()
noexcept{
if (_commit)_release();}RAII(RAII&& rv)
noexcept : _commit(rv._commit),_release(rv._release){rv._commit =
false;};RAII& commit(
bool c =
true)
noexcept;
protected:
std::function<
void()> _release;
private:RAII(
const RAII&);RAII&
operator=(
const RAII&) =
delete;
bool _commit;};
inline RAII& RAII::commit(
bool c =
true)
noexcept{ _commit = c;
return *
this; };
template<
typename T>
class RAIIVar{
public:
typedef std::function<T()> AcquireType;
typedef std::function<
void(T &)> ReleaseType;
explicit RAIIVar(AcquireType acquire, ReleaseType release)
noexcept :_resource(acquire()),_release(release){}RAIIVar(RAIIVar&& rv) :_resource(
std::move(rv._resource)),_release(
std::move(rv._release)){rv._commit =
false;}~RAIIVar()
noexcept{
if (_commit)_release(_resource);}RAIIVar<T>& commit(
bool c =
true)
noexcept{ _commit = c;
return *
this;};T& get()
noexcept{
return _resource; }T&
operator*()
noexcept{
return get();}
template<
typename _T = T>
typename std::enable_if<
std::is_pointer<_T>::value, _T>::type
operator->()
const noexcept{
return _resource;}
template<
typename _T = T>
typename std::enable_if<
std::is_class<_T>::value, _T*>::type
operator->()
const noexcept{
return std::addressof(_resource);}
private:
bool _commit =
true;T _resource;ReleaseType _release;};
template<
typename RES,
typename M_REL,
typename M_ACQ>RAII make_raii(RES & res, M_REL rel, M_ACQ acq,
bool default_com =
true)
noexcept{
static_assert(
std::is_class<RES>::value,
"RES is not a class or struct type.");
static_assert(
std::is_member_function_pointer<M_REL>::value,
"M_REL is not a member function.");
static_assert(
std::is_member_function_pointer<M_ACQ>::value,
"M_ACQ is not a member function.");assert(
nullptr != rel &&
nullptr != acq);
auto p_res =
std::addressof(
const_cast<
typename no_const<RES>::type&>(res));
return RAII(
std::bind(rel, p_res),
std::bind(acq, p_res), default_com);}
template<
typename RES,
typename M_REL>RAII make_raii(RES & res, M_REL rel,
bool default_com =
true)
noexcept{
static_assert(
std::is_class<RES>::value,
"RES is not a class or struct type.");
static_assert(
std::is_member_function_pointer<M_REL>::value,
"M_REL is not a member function.");assert(
nullptr != rel);
auto p_res =
std::addressof(
const_cast<
typename no_const<RES>::type&>(res));
return RAII(
std::bind(rel, p_res), [] {}, default_com);}}
總結
以上是生活随笔為你收集整理的C++之RAII机制的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。