最近开始看《Effective C++》,为了方便以后回顾,特意做了笔记。若本人对书中的知识点理解有误的话,望请指正!!!
我们来模拟投资行为,投资类的基类为 Investment
,各种各样的投资类型继承自 Investment
class Investment { ... };//投资类型的基类
进一步假设,Investment
的派生类对象都通过一个工厂函数创建:
Investment* createInvestment();//返回指针,指向创建的对象;为了简化而省略某些参数
在 createInvestment()
内 new
出新的对象,一旦不用了需要用 delete
来释放资源。
void f()
{
Investment* pInv = createInvestment(); //调用工厂函数创建对象
... //使用pInv
delete pInv; //释放pInv所指的对象
}
虽然 f()
中有做了 delete
操作,但 ...
区域的代码可能会导致不会执行 delete
操作。如 ...
中过早的 return
语句或抛出异常;createInvestment()
和 delete
操作位于某循环内,而该循环于某个 continue
语句过早退出。
解决方法:使用智能指针(头文件 <memory>
)
智能指针主要用于管理在堆上分配的内存,它将普通的指针封装为一个栈对象。当栈对象的生存周期结束后,会在析构函数中释放掉申请的内存,从而防止内存泄漏。C++ 11中最常用的智能指针类型为 shared_ptr
,它采用引用计数的方法,记录当前内存资源被多少个智能指针引用。该引用计数的内存在堆上分配。当新增一个引用时计数加1,当过期时引用计数减一。只有引用计数为0时,智能指针才会自动释放引用的内存资源。对 shared_ptr
进行初始化时不能将一个普通指针直接赋值给智能指针,因为一个是指针,一个是类。可以通过 make_shared
函数或者通过构造函数传入普通指针。并可以通过get函数获得普通指针。
void f()
{
shared_ptr<Investment> pInv(createInvestment()); //构造函数生成智能指针
auto p = make_shared<Investment>(createInvestment()); //make_shared创建智能指针
... //使用pInv
} //在智能指针的析构函数中释放资源
createInvestment()
返回的是“未加工指针”是对资源泄漏的一个死亡邀约,因为调用者很容易在这个指针身上忘记调用 delete
或 忘记将 createInvestment()
返回的指针存储于智能指针对象内,因此需要对 createInvestment()
进行优化,令它返回智能指针对象。(详见条款18)
“以对象管理资源”的两个关键点:
-
获得资源后立刻放进管理对象内。
“以对象管理资源”的观念常被称为“资源取得时机便是初始化时机”(Resource Acquisition Is Initialization,RAII)
-
管理对象运用析构函数确保资源被释放。
shared_ptr
在其析构函数内做 delete
操作,而不是 delete[]
操作(条款16对两者的不同有描述)。这一意味在动态分配而得的 array
身上使用 shared_ptr
是个坏主意。
Note:
- 为防止资源泄漏,请使用智能指针对象,它们在构造函数中获得资源并在析构函数中释放资源。