Effective C++之三:以对象管理资源
来源:互联网 发布:linux scp 下载文件夹 编辑:程序博客网 时间:2024/05/21 21:50
条款13 以对象管理资源
(1)
为防止资源泄露,请使用RAII(资源获取时机便是初始化时机)对象,它们在构造函数中获得资源并在析构函数中释放资源。
“以对象管理资源”的观念常被称为“资源取得时机便是初始化时机”(RAII),因为我们总是在获得资源后于同一句话以它初始化(或赋值)某个管理对象。
void f()
{
Investment* pInv = createInvestment(); //返回动态分配的对象。调用者有责任删除它。
...
delete pInv; //释放所指的对象
}
管理对象在离开区块会被销毁,自然会调用管理对象的析构函数,一时资源被释放。
void f()//“以对象管理资源”的观念常被称为“资源取得时机便是初始化时机”(RAII),因为我们总是在获得资源后于同一句话以它初始化某个管理对象。
{
auto_ptr<Investment> pInv(createInvestment()); //createInvestment()返回的资源被当做其管理者auto_ptr的初值
...
}
(2)多个auto_ptr不能同时指向同一对象。
auto_ptr<Investment> pInv1(createInvestment());
auto_ptr<Investment> pInv2(pInv1); //现在pInv2指向对象,pInv1设为null
pInv1 = pInv2; //现在pInv1指向对象,pInv2设为null
(3)多个shared_ptr可以同时指向同一对象。
void f()
{
shared_ptr<Investment> pInv(createInvestment());
shared_ptr<Investment> pInv2(pInv1); //现在pInv2与pInv1只向同一对象
pInv1 = pInv2; //同上
...
}//pInv2与pInv1同时被销毁,所指对象也被自动销毁
(4)不能在动态分配的数组上使用auto_ptr和shared_ptr。
因为vector和string几乎总是可以取代动态分配而得的数组。
Boost::scoped_array 和 boost::shared_array classes也可以满足。
(5)记住!!!只能括号调用构造函数, = 调用会失败
shared_ptr<int> sp1 =new int(2); //编译过不了
shared_ptr<int> sp2(newint(3)); //成功
条款14 在资源管理类中小心copying行为
复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为。
void lock(Mutex* pm);
void unlock(Mutex* pm);
class Lock{
public:
explicit Lock(Mutex* pm):mutexPtr(pm)
{
lock(mutexPtr);
}
~Lock()
{
unlock(mutexPtr);
}
private:
Mutex* mutexPtr;
};
int main()
{
Metux m;
...
{ //某个区块里
Lock ml1(&m); //锁定互斥锁
Lock ml2(ml1); //将ml1复制到ml2身上,会发生什么事?
}
return0;
}
下面是解决办法:普遍而常见的RAII class copying行为是: 抑制copying、施行引用计数法(reference counting)。不过其他行为也都可能被实现。
(1)禁止复制
使用条款6的办法:将copying构造函数设为private。
(2)对底层的资源使用“引用计数法”。
注意:shared_ptr的缺省行为是“引用次数为0时便删除其所指物”。但是shared_ptr允许指定“删除器”--一个函数或者函数对象,当引用次数为0时便调用。
void lock(Mutex* pm);
void unlock(Mutex* pm);
class Lock{
public:
explicit Lock(Mutex* pm): mutexPtr(pm, unlock) //以某个Mutex初始化shared_ptr,并以unlock函数为删除器
{
lock(mutexPtr.get()); //条款15有get(),返回智能指针内部的原始指针
}
//注意:当前不再需要声明析构函数。因为类的析构函数(无论编译器生成还是自己写的)会自动调用其non-static成员变量(mutexPtr)的析构函数
//而mutexPtr的析构函数会在互斥器的引用次数为0时自动调用shared_ptr的删除器(本例是unlock)。
private:
shared_ptr<Mutex> mutexPtr; //使用shared_ptr替换原始指针
};
(3)复制底部资源。针对一份资源拥有其任意数量的复件。
在复制资源管理对象,也可以复制其所包含的资源。也就是说进行的是深入拷贝。
(4)转移底部资源的拥有权:auto_ptr
条款15 在资源管理类中提供对原始资源的访问
APIs(比如说智能指针)往往要求访问原始资源(raw resources,也就是那个原始的指针), 所以每一个RAII class应该提供一个“取得其所管理之资源”的方法。
对原始资源的访问可能经由显示转换或隐式转换。一般而言显式转换(定义一个成员函数get)比较安全,但隐式转换对客户比较方便。
(1)shared_ptr提供get成员函数,执行显式转换,返回其所包含之原始资源。
int daysHeld(const Investment* pi);
shared_ptr<Investment> PInv(creatInvestment());
int days = daysHeld(PInv); //错误!
int days = daysHeld(PInv.get());//shared_ptr提供get成员函数,执行显式转换,返回其所包含之原始资源。
(2)shared_ptr也重载操作符 "->" "*",允许隐式转换至底部原始指针。
class Investment{
public:
bool isTaxFree()const;
...
};
shared_ptr<Investment> pi1(creatInvestment());
bool taxable1 = !(pi1->isTaxFree());
auto_ptr<Investment> pi2(creatInvestment());
bool taxable2 = !((*pi2).isTaxFree());
(3)对于返回类对象里面的一个原始资源,有两种方式。
void releaseFont(FontHandle fh);
class Font{
public:
explicit Font(FontHandle fh):f(fh){}
~Font(){releaseFont(f);}
FontHandle get() const //方式一:显式转换函数。最主要的目的是防止资源(FontHandle)泄露
{return f;}
operator()const //方式二:另一个方法是Font提供一个隐式转换函数
{return f;}
private:
FontHandle f;
};
条款16 成对使用new和delete时要采取相同形式
(1)
new 有两件事:
1、内存被分配
2、一或多个构造函数被调用
delete 两件事:
1、一或多个析构函数被调用
2、内存被释放
(2)
如果你在new表达式中使用[],必须在delete表达式中也使用[]。
如果new不使用[],delete也一定不使用!
(3)
typedef string AddressLines[4];//尽量不要对数组形式做typedef。改用vector。typedef用法还需要熟悉。 特别是这种[4]写在后面的形式。
int main()
{
string* pal =new AddressLines; //new AddressLines 相当于 new string[4]
delete pal; //错误
delete[] pal; //正确
return0;
}
条款17 以独立语句将new对象置入智能指针
(1)
以独立语句将new对象置入智能指针。如果不这样做,其他部分可能会有异常抛出,在资源被创建与资源被转化为资源管理对象之间可能发生异常干扰,可能导致资源泄露。
int priority();
void processWidget(shared_prt<Widget> pw,int priority);
processWidget(shared_prt<Widget> (new Widget), priority());
//上面这个句话分为三部:
//1、调用priority()
//2、执行 new Widget
//3、执行shared_ptr构造函数
//但是编译器完成这三步的顺序可能会改变,改为 2 1 3。如果在priority()出错,那new出来的指针就回遗失,引发资源泄露。
//所以应该改为
shared_prt<Widget> pw(new Widget); //独立语句将newd对象存储于智能指针内
processWidget(pw, priority());
- Effective C++之三:以对象管理资源
- C++内存管理------>以对象管理资源(Effective C++)
- 【Effective c++】条款13:以对象管理资源
- 《Effective C++》学习笔记条款13 以对象管理资源
- Effective C++——》条款13:以对象管理资源
- Effective C++:条款13:以对象管理资源
- 读书笔记《Effective C++》条款13:以对象管理资源
- <Effective C++> (Item 13-15): 以对象管理资源
- Effective C++ 学记之13 以对象管理资源
- Effective C++读书笔记之十三:以对象管理资源
- Effective C++ ----以对象管理资源
- Effective C++读后感:以对象管理资源
- effective c++ 以对象管理资源
- C++中以对象管理资源<auto_ptr>(13)---《Effective C++》
- Effective C++(13) 用对象管理资源
- effective c++条款13-17 “以对象管理资源”之RAII浅析
- effective c++条款13-17 “以对象管理资源”之auto_ptr源码分析
- effective c++条款13-17 “以对象管理资源”之shared_ptr浅析
- 构建ip代理池
- 干货 | Elasticsearch5.X Mapping万能模板
- The node about the project of DJ
- oracle comment on的用法
- SecureCRT工具下sftp的用法
- Effective C++之三:以对象管理资源
- 常用的三种获取程序运行时间的方法
- 什么是架构
- Http协议浅析
- 【OpenGL ES】帧缓冲区对象FBO
- Matplotlib for presenting results(论文画图matplotlib jupyter文档)
- SpringMVC解决前台向后台传输的乱码问题
- DPDK源码学习——初始化
- 计算机视觉与深度学习(3)