effective c++读书笔记(三)

来源:互联网 发布:sportsdt体育大数据 编辑:程序博客网 时间:2024/05/17 00:56

资源管理

资源就是你用了它,最后还要把它换回去。常见的资源包括:内存,文件描述器,互斥锁,图形界面中的字形和笔刷,数据库连接,以及网络sockets。

以对象管理资源

class Investment{ // ...};Investment* createInvestment();void f(){    Investment* pInv = createInvestment();    //...    delete pInv;}

上述代码如果在delete前过早的执行return语句,或由于continue,goto等过早的退出。或提前抛出异常,等情况下,delete语句将不会执行,无法释放叼申请的内存,导致内存泄漏。或者由于维护人员对程序的理解不够深入,而加入了异常处理或这提前return 的语句都将导致内存泄漏的问题。
为了确保createInvestment返回的资源总是被释放。应该将资源放进对象内,当控制流离开f函数是,该对象的析构函数会自动释放那些资源。

void f(){    std::auto_prt<Investment> pInv(createInvestment());    //...}

使用上述的方法可以避免内存泄漏的问题。体现了两个关键的想法:
1:获得资源后,立刻放进管理对象内;资源取得时机辨识初始化时机。
2:管理对象运用析构函数确保资源被释放

在资源管理类中小新coping行为

上条规则中所说的管理资源的方法都是针对heap-based类型资源的方法,但是并非所有资源都是heap-based,对于那些资源而言,智能指针就不再适合作为资源管理者。有的时候,需要自己建立自己的资源管理类。

//C API 函数处理类型为Mutex的互斥器对象。void lock(Mutex *pm);//锁定pm所指的互斥器void unlock(Mutex *pm); //将互斥器解除锁定//有时为了不忘记将一个被锁住的Mutex解锁,希望自己建立一个管理机锁class Lock{public:    explicit Lock(Mutex *pm): mutexPtr(pm){        lock(MutexPtr);    }    ~Lock{ unlock(mutexPtr);}private:    Mutex *mutexPtr;};Mutex m;//...{    Lock m1(&m); //运行完成后自动解锁}//但是当出现Lock对象复制的情况下Lock m11(&m);Lock m12(m11);

针对上面的问题有两种选择:1:禁止赋值 可以将copying操作声明为private的。2:对底层资源祭出“引用计数法”
复制底部资源:有时候,只要你喜欢,可以针对一份资源拥有任意数量的复件,需要资源管理类的唯一理由是:当不再需要某个复件时,确保把它释放了。复制资源管理对象时,进行的是深度拷贝。
转移底部资源的拥有权:有时只希望只有一个对象指向未加工资源,即auto_ptr奉行的复制意义。
coping 函数可能被编译器自动创建出来,因此除非编译器版本做了你想要的做的事情,否则你得自己编写他们

在资源管理类中提供对原始资源的访问

一般来说可以通过资源管理类来进行处理和资源之间的所有互动,但是有的时候你必须绕开资源管理类直接访问原始资源。在此种情况下,应该在资源管理类中提供对于原始资源的访问方法,一般有显示类型转换,和隐式类型转换两种方法。显示类型转换一般情况下要比隐式转换方法更加的安全。

std::shared_ptr<Investment> pInv(createInvestment());int daysHeld(const Investment *pi);int days = daysHeld(pInv); //false

因为daysheld需要的是Investment*指针,但是传递给他的是shart_ptr的对象。
可以通过加入get成员函数进行显示的类型转换。int days = daysHeld(pInv.get());

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

如果new表达式中使用[],必须响应的delete表达式中使用[]。同理反之。

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

因为如果不这样做,一旦异常被抛出,有可能导致难以察觉的资源泄漏问题。

int priority();void processWidget(std::shared_ptr<Widget>pw, int priority());processWidget(new Widget, priority()); //false 不能通过编译,因为shared_ptr构造函数需要一个原始指针,但该构造函数是个explicit构造函数,无法进行隐式转换processWidget(std::shared_ptr<Widget>(new Widget), priority()); //可能导致内存泄漏std::shared_prt<Widget> pw(new Widget);processWidget(pw, priority()); //true

processWidget(std::shared_ptr<Widget>(new Widget), priority());编译器的执行顺序不一定,如果调用priority()函数在shared_ptr构造函数之前。然后priority()函数抛出了异常,会导致new Widget的指针丢失,导致内存泄漏。

原创粉丝点击