猫猫哥

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
//############################################################################
/* 资源获取即是初始化 (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);
posted on 2018-12-24 00:13  猫猫哥  阅读(630)  评论(0编辑  收藏  举报