标签:tin int 深拷贝 分支 取值 目标 reference 复制 red
1. 资源并没有还给系统。
概述中已经说到,资源用完之后要还给系统。 我们考虑以下函数会发生什么:
void f()
{
Investment * pInv = createInvestment();
...
delete pInv;
}
1.1 倘若我们在delete之前的函数中有一个分支,会进行return。那么我们就永远不会执行delete,这样函数执行结束之后并没有将动态分配的资源还给系统,会有内存泄漏的风险。
1.2 倘若中间有goto语句,也是如此。
1.3 倘若抛出了异常,delete函数也无法被执行到。
2.1 使用智能指针————auto_ptr.
void f()
{
std::auto_ptr<Investment> pInv(createInvesment());
...
}
当智能指针出了函数的作用域,会调用其析构函数自动删除pInv.
这个简单例子示范“以对象管理资源”的两个关键想法:
auto_ptr的一个性质:
auto_ptr<Investment> pInv1(createInvestment()); //pInv1指向对象
auto_ptr<Investment> pInv2(pInv1); //pInv指向对象,pInv1为null
pInv1 = pInv2; //pInv1指向对象,pInv2为null
这块代码已经注释,也就是aotu_ptr的性质:
如果通过copy构造函数或copy assignment函数复制它们,原来的auto_ptr将变成null,新的指向才指向对象。
原因:
如果让多个auto_ptr指向了同一个对象,那么如果多个auto_ptr的析构函数调用,会对一个对象进行多次删除,但实际上第一次删除之后就不存在了,后面的删除会造成未定义的行为。
2.2 使用“引用计数型智慧指针”替代auto_ptr
也就是shared_ptr:
void f()
{
shared_ptr<Investment> pInv1(createInvestment()); //pInv1指向对象
shared_ptr<Investment> pInv2(pInv1); //pInv2指向对象,pInv1也指向对象
pInv1 = pInv2; //pInv1指向对象,pInv2也指向对象
}
在这个函数里面,shared_ptr允许多个指针指向同一个对象。它会对指针进行计数,直到计数为0的时候才会调用析构函数,删除对象。所以并不会出现多次删除同一个对象的情况。
注意:
auto_ptr和shared_ptr在其析构函数中做的都是delete操作而没有delete[]操作。所以我们要注意别在动态分配的array中使用这两个指针。
auto_ptr<string> aps(new string[10]);
shared_ptr<int> spi(new int[1024]);
这两个操作都是十分危险的。
为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源。
两个常被使用的RAII classes分别是shared_ptr和auto_ptr.前者是较佳的选择,因为其copy行为比较直观。若选择auto_ptr,复制动作会使它指向null.
当我们使用shared_ptr的时候,当引用计数变为0时,会删除这个对象。但实际情况里,我们可能不想要删除。
比如一个互斥锁的类,构造的时候就加锁,析构的时候解锁,这样也符合RAII对象的特性。
class Lock
{
public:
explicit Lock(Mutex *pm)
:mutexPtr(pm)
{
lock(mutexPtr); // 获得资源
}
~Lock()
{
unlock(mutexPtr); // 释放资源
}
private:
Mutex *mutexPtr;
}
现在让我们看看,在调用的时候进行copy的行为会造成什么:
Mutex m;
...
{
Lock m1(&m);
...
}
这段代码是正确的行为,在出作用域的时候,析构函数被调用,就会自动解锁。
但是如果客户端出现copy行为:
Lock m1(&m);
Lock m2(m1);
这会造成m2还在使用资源的时候,假如m1析构函数调用了,那么资源就被释放了,m2也就无法使用了。
解决方法:
对底层资源祭出“引用计数法”。 这个方法要注意shared_ptr在计数为0的时候会删除这个对象,但是我们只需要释放它,所幸shared_ptr允许我们指定一个删除器。我们可以改成:
class Lock转移底部资源所有权。 确保只有一个RAII对象指向一个资源,复制时候资源的所有权从被复制物转向目标物。 可以参考auto_ptr的做法,讲原来的指针置为null,确保只有一份资源被使用。
复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定对象的copying行为。
普遍而常见的RAII class copying行为是:抑制copying、施行引用计数法(reference counting)。不过其他行为也都可能被实现。
shared_ptr获得原始指针,只需要调用get函数即可。
shared_ptr
shared_ptr和auto_ptr都重载了指针取值的方法。
class Investment
{
public:
bool isTaxFree() const;
...
}
此时执行:
shared_ptr<Investment> pInv(createInvestment());
bool taxFree1 = pInv->isTaxFree();
bool taxFree2 = (*pInv).isTaxFree();
以上"->"运算符和"."运算符都是适用的。
标签:tin int 深拷贝 分支 取值 目标 reference 复制 red
原文地址:https://www.cnblogs.com/love-jelly-pig/p/9629800.html