C++進階--RAII 資源獲取即初始化
阿新 • • 發佈:2018-12-24
//############################################################################ /* 資源獲取即是初始化 (RAII) * * 使用物件來管理資源: (利用棧回退時一定會釋放棧上物件的機制) * 記憶體,硬體裝置,網路控制代碼等 */ Mutex_t mu = MUTEX_INITIALIZER; void functionA() { Mutex_lock( &mu ); ... // 做一系列事情 Mutex_unlock( &mu ); // 是否一定會被執行 } /* * 解決方法: */ class Lock { privat: Mutext_t* m_pm; public: explicit Lock(Mutex_t *pm) { Mutex_lock(pm); m_pm = pm;}; ~Lock() { Mutex_unlock(m_pm); }; } void functionA() { Lock mylock(&mu); ... // 做一系列事情 } // mutex總是會被釋放,當myloack物件從棧上被銷燬的時候 /* 結論: * * 在異常丟擲後唯一保證會被執行的程式碼是 * 棧上物件的解構函式 * * 所以資源管理要和合適的物件生命週期結合在一起 * 從而達到自動去分配和回收的目的 */ /* Note 1: * 另一個RAII的例子: tr1:shared_ptr */ int function_A() { std::tr1::shared_ptr<dog> pd(new dog()); ... } // 當pd走出作用域時dog會被銷燬 (沒有指標指向pd). // Note 2: // 另一個例子: class dog; class Trick; void train(tr1::shared_ptr<dog> pd, Trick dogtrick); Trick getTrick(); int main() { // tr1::shared_ptr<dog> pd(new dog()); train(tr1::shared_ptr<dog> pd(new dog()), getTrick()); } //問題: 上面程式碼有什麼問題? // 引數傳遞的操作順序由編譯器決定 // 如果train()函式的引數傳遞按如下順序進行會怎麼樣: // 1. new dog(); // 2. getTrick(); // 3. construct tr1::shared_ptr<dog>. // 第2步如果丟擲異常,記憶體洩漏 // 結論:不要將物件存到共享指標的操作跟其他宣告混到一起 /* Note 3: 如果資源的管理物件被拷貝會怎樣? */ Lock L1(&mu); Lock L2(L1); /* Solution 1: * 禁止拷貝. 見【不讓編譯器生成類函式】 */ /* Solution 2: * 使用tr1::shared_ptr對資源進行引用計數 */ template<class Other, class D> shared_ptr(Other * ptr, D deleter); // D的預設值是"delete": std::tr1::shared_ptr<dog> pd(new dog()); class Lock { private: std::tr1::shared_ptr<Mutex_t> pMutex; public: explicit Lock(Mutex_t *pm):pMutex(pm, Mutex_unlock) { Mutex_lock(pm); // The second parameter of shared_ptr constructor is "deleter" function. }; } } Lock L1(&mu); Lock L2(L1);