Effective C++|Chapter 3:资源管理

Item13:以对象管理资源

  • 熟记:任何向系统申请得来的资源,不再使用它们时,必须将它们还给系统。

  • 不能倚靠程序员会谨慎写程序释放资源。如下:尽管在f()函数有delete pInv,但是如果程序中间有控制流return / goto,而未delete pInv,那么就会导致资源泄漏。

    void f()
    {
    	Investment* pInv = createInvestment(); 
    	...
    	delete pInv;   
    }
    
  • 解决办法:使用标准程序库提供的“智能指针”auto_ptr,其析构函数自动对其所指对象调用delete。

    std::auto_ptr pInv(createInvestment());
    这个例子表明“以对象管理资源”的两个关键想法:

    • 获得资源后立刻放进管理对象:即“资源取得时机便是初始化时机”(Resource Acquisition Is Initialization; RAII)
    • 管理对象运用析构函数确保资源被释放:不管控制流如何离开区块,一旦对象被销毁(例如当对象离开作用域),其析构函数自然会被自动调用。
  • “智能指针”auto_ptr的性质:若通过copy构造函数copy assignment操作符复制它们,它们会变成null,而复制所得的指针将取得资源的唯一拥有权!【防止多个auto_ptr指向同一对象,当对象被删除一次后,其他指针会发生“未定义行为”】

    std::auto_ptr<Investment> pInv1(createInvestment());
    // pInv1会变为null
    std::auto_ptr<Investment> pInv2(pInv1); 
    // pInv2会变为null
    pInv1 = pInv2;
    
  • 也可以使用shared_ptr。

  • shared_ptr是一种“引用技术型智慧指针”(reference-counting smart pointer; RCSP)。其特点是:持续跟踪共有多少对象指向某笔资源,并在无人指向它时自动删除该资源。【类似垃圾回收,但无法打破环状引用

	std::tr1::shared_ptr<Investment> pInv1(createInvestment());
	// pInv1和pInv2指向同一对象
	std::tr1::shared_ptr<Investment> pInv2(pInv1); 
	pInv1 = pInv2;

Item16:成对使用new和delete时要采取相同形式

  • 错误示例:
    stringArray是一个指向数组的指针,当使用delete时,只调用一次析构函数释放一个string对象【string[0]】,其余99个对象未被释放。

    string* stringArray = new string[100];
    delete stringArray;
    
  • 正确规则:
    如果new时使用[],则delete时也使用[];否则,不使用[]。

    string* stringPtr1 = new string;
    string* stringPtr2 = new string[100];
    delete stringPtr1;   // 删除一个对象
    delete[] stringPtr1;  // 删除一个由对象组成的数组
    
  • 要避免的示例:【结论:最好不要对数组形式做typedefs动作,而应使用vector< string >】

    typedef string AddressLines[4];  // AddressLines是地址有4行,每行是一个string的数据类型
    string* pal = new AddressLines; // new AddressLines返回一个string*,就像new string[4] 一样
    delete pal;  // 行为未有定义
    delete[] pal;	// 应该使用delete[] 删除
    

Item17:以独立语句将newed对象置入智能指针

  • 若调用如下函数:

    // 函数声明
    int priority();
    void processWidget(std::tr1::shared_ptr<Widget> pw, int priority);
    // 这个语句无法通过编译。tr1::shared_ptr构造函数需要一个原始指针(raw pointer),但该构造函数是个explicit构造函数,无法进行因式
    processWidget(new Widget, priority());
    
    //而应写成
    processWidget(std::tr1::shared_ptr<Widget> (new Widget), priority());
    
    • 执行顺序:【“new Widget”一定执行于std::tr1::shared_ptr之前,priority()可以排在第一或第二或第三执行】假设按照如下顺序调用:
      • (1) 执行"new Widget";
      • (2) 调用priority
      • (3) 调用std::tr1::shared_ptr构造函数
    • 问题:如果 调用priority 的过程出现异常,那么new Widget返回的指针将会遗失,造成资源泄漏。
    • 正确作法:【使用分离语句】
      std::tr1::shared_ptr<Widget> pw(new Widget);
      processWidget(pw, priority());
      
  • 请记住:

    • 以独立语句将newed对象存储于智能指针内。否则,一旦异常抛出,有可能导致难以察觉的资源泄漏。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值