为了解决c++中的内存泄露问题,c++98引入了auto_prt的解决方案。
void func()
{
classA* prt = new classA;
.......//perform some operations
delete prt;
}
通常我们会忘记执行delete操作,有时候即使没有忘记delete,但是如果在中途产生异常,程序会立即终止,函数即刻退出,这个时候,还没有走到delete语句处,这样也造成了内存泄露。
在函数退出的过程中,栈中的局部变量都会被释放,所以如果有一个局部的指针,当它被释放的时候,同时释放其所指向的对象,那么不就避免了内存泄露了吗!于是便产生了auto_prt这种智能指针对象。
auto_prt使用的原理是所有权的转移,即任何一个对象都只对应唯一一个auto_prt,绝不会出现多个auto_ptr共享同一个对象的情况。
但是auto_prt同时具有一些缺陷,首先,执行以下操作:
缺陷1:
std::auto_prt<classA> prt1(new classA);
std::auto_prt<classA> prt2 = prt1; //此时赋值操作中,进行了所有权的转移,使prt1交出了所有权,只剩一个null指针,所以如果以后的代码再对prt1进行一些操作(比如调用classA中的成员函数等),将产生未定义的行为。
缺陷2:
auto_prt使用的是delete进行对象释放,而不具备delete [ ]的变体,所以不能将auto_prt用于指针数组,同时不能将其用于静态内存分配的对象,只能用于new出来的对象。
缺陷3:
auto_prt由于是所有权的转移,所以在赋值和复制的时候,会照成原来的所有者失效,所以不能将其容器中,容器要求所保存的类型定义复制和赋值操作符,使它们表现得类似于内置类型的操作符:在复制(或者赋值)之后,两个对象必须具有相同值。
基于以上的种种问题,c++11摒弃了auto_prt,而重新引入了三种只能指针,shared_prt, unique_prt, weak_prt.
1:
shared_prt:其实现原理与auto_ptr完全不同,他是采用引用计数的原理实现,shared_ptr对象内部保留一个计数变量,每赋值或复制一次,变量+1,
指针过期,计数-1,当最后一个指针过期,即计数为0时,释放所指向的对象。shared_ptr保证了多个指针同时指向一个对象,实现了对象资源共享。
2:upique_ptr是auto_ptr的升级版本,它解决了auto_ptr的缺陷1和缺陷2.对于缺陷1:unique_ptr直接禁止赋值操作,但是如果在赋值的时候,源unique_ptr是一个临时右值,编译器确实允许这种操作的,原则就是,如果源unique_ptr会存在一段时间,那么,该操作就是非法的,因为这样就会产生悬垂指针,造成缺陷1的错误,如果源unique_ptr只是临时对象,那么将是合法的。
exp.
std::unique_ptr<classA> prt1(new classA);
std::unique_ptr<classA> prt2 = ptr1; // not allowed
std::unique_ptr<classA> ptr3 = std::unique_ptr<classA>(new classA); //allowed
对于缺陷2:unique_ptr用于了new[] delete[] , new delete两种版本,所以可以将其指向数组。
对于缺陷3,unique_ptr任然不能直接用于容器,单可以间接使用,比如依靠std::move(),将源unique_ptr赋值给目标unique_ptr.