//条款13:以对象管理资源 // 1.C++程序中最常使用的资源就是动态分配内存,并且还包括文件描述器,互斥锁,GDI对象、数据库连接、网络socket等。不管哪一种资源,当不再使用的时候必须将其归还给系统。 // 2.诸如以下代码: void fun(int *p) { ... ... delete p; }//以上代码中,p是指向动态分配的内存,在此函数中对p进行使用和释放,但是在函数中可能有一个过早的return语句导致delete语句不能被执行,或者产生一个异常而导致delete语句不能被执行 // 3.当然,谨慎的编写程序可以避免上述错误,但是必须考虑到,代码可能在时间渐渐过去后被修改,一旦软件开始接受维护,可能会被添加欠缺考虑的return等语句而导致delete不能被正常执行 // 4.为了确保上述函数中指针p所指的对象能被正确释放,正确的做法可以是将指针p放入一个对象内,该对象的析构函数会自动释放那些资源。 // 5.利用智能指针可以方便的实现利用对象来管理动态内存资源。经过测试,由于智能指针析构复杂,当需要考虑效率的时候,不如将资源放入一个简单的自定义类中进行管理。 // 6.对于其他资源,可以建立一个资源类,在析构函数中进行资源的释放。 //条款14:在资源类中小心复制行为(利用另一个对象初始化或者用其赋值) // 1.禁止复制。如同类unique_ptr那样,比如一个资源类包含了互斥锁,那么这个类就应该禁止复制。通过将一系列的拷贝操作声明为private并且不进行定义来实现禁止复制。 // 2.引用计数法。如同类shared_ptr那样,将一直有资源,直到它的最后一个使用者被销毁。实际上使用shared_ptr类并传入自己的删除器可以很方便的实现对资源进行引用计数法管理。 // 3.复制底部资源。有时候需要针对一份资源,需要拥有其任意数量的副本,此时进行对资源的深拷贝。 // 4.转移底部资源。将资源从一个拥有者转移给另一个拥有者。即移动的概念。当对unique_ptr进行std::move的时候就是这种情况。 //条款15:在资源类中提供对原始资源的直接访问 // 1.存在很多函数需要访问原始资源,所以每个资源类都应该提供对原始资源直接访问的方法 // 2.智能指针对->和*进行了重载,它们允许隐式转换至底部原始指针。 unique_ptr<string> pStr(new string("szn")); int size = pStr->size(); //size = 3 // 3.智能指针的get()成员函数也可以直接获取智能指针所管理的原始资源。 //条款16:成对使用new和delete时要采取相同的形式。 // 1.使用new[]分配内存的时候,会有多个构造函数被调用,当不慎使用delete删除new[]分配的内存时,对应的析构函数的调用次数会出错。 // 2.当使用typedef的时候特别要小心 //17.以独立的语句将new出来的对象放入智能指针中 // 1.考虑如下语句: fun(shared_ptr<int>(new int), fun1()); // 由于函数形参的调用时机不同,上述函数的调用方式可能是这样的:首先执行new int,然后执行fun1(),最后执行shared_ptr的构造函数,当在fun1()中产生异常,则将导致内存泄露。 // 2.避免上述问题的方法很简单: shared_ptr<int> pInt(new int); fun(pInt, fun1());