【Effective C++】3.资源管理

发布时间:2024年01月21日

Item13 以对象管理资源

资源:

  • 内存、文件描述符、互斥锁、数据库链接和网络socket等,用了需要还给操作系统
  • 异常、函数多重返回路径和程序员不恰当的改动,会导致资源没有释放

考虑以下场景,delete都不会执行,资源都会泄漏,

  • 如果在do_something过程出现return;
  • 或者do_something过程抛出异常;
  • 或者delete语句在循环内,被continue;
class Investment {...}; // 投资行为的父类
Investment* creatInvestment(); // 创建对象的工厂
void f() {
    Investment* pInv = creatInvestment();
    // do_something
    delete pInv;    
}

解决思路,以对象管理资源:

  • 获得资源后立即放进管理对象内(RAII,Resource Acquisition Is Initialization);
  • 管理对象运用析构函数自动调用的机制确保资源被释放。

上述函数可以使用智能指针的方式修改

#include <memory>
class Investment {};
Investment* creatInvestment() {
    return new Investment;
}
void f() {
    // std::auto_ptr<Investment> pInv(creatInvestment()); // c++98标准
    std::shared_ptr<Investment> pInv(creatInvestment());  // c++11标准
}


/*
 * auto_ptr 为了防止同一个对象被删除多次,通过拷贝和或者拷贝赋值,该指针会变为null
 * 与stl容器要求的正常复制行为不兼容
 * c++11 中unique_ptr会静止拷贝操作 
int main() {
    std::auto_ptr<Investment> pInv1(creatInvestment());
    std::auto_ptr<Investment> pInv2(pInv1); 
    if (pInv1.get() == nullptr) std::cout << "pInv1 is null\n";
    if (pInv2.get() != nullptr) std::cout << "pInv2 is not null\n";

    return 0;
}
*/

注意事项:不能用来管理动态分配的数组,因为底层调用的时delete,而不是delete []

int main() {
    std::shared_ptr<std::string> aps(new std::string[10]);
    return 0;
}
/*
 * 报错内容
munmap_chunk(): invalid pointer
Aborted (core dumped)
*/

Item17 以独立语句将new对象放入智能指针

考虑以下场景:

class Widget {};
int priority() {return 0;}
void processWidget(std::shared_ptr<Widget> pw, int priority) {}

int main() {
    // processWidget(new Widget, priority()); //  error: could not convert ‘(Widget*)operator new(1)’ from ‘Widget*’ to ‘std::shared_ptr<Widget>’
    // processWidget(std::shared_ptr<Widget>(new Widget), priority());
    // std::shared_ptr<Widget> pw(new Widget);
    // processWidget(pw, priority());
    processWidget(std::make_shared<Widget>(), priority());
    return 0;
}

processWidget函数可能的执行顺序(取决于编译器,保证1在3前面,2的执行顺序不确定):

  1. 执行?new Widget;
  2. 调用 priority();
  3. 调用?std::shared_ptr 构造函数

当调用?priority() 发生异常,new Widget 返回的指针将丢失,资源不能被正确释放

解决方案:

  • 以独立的语句将对象存储在智能指针内;
  • C++11标准中可以使用 std::make_shared<Widget>() 合并两个过程。
文章来源:https://blog.csdn.net/GouDanAndOcean/article/details/135729013
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。