先来看一个例子:
void remodel(std::string & str)
{
std::string * px = new std::string(str);
...
str = ps;
return;
}
你是不是似乎发现了什么呢?(手动滑稽)没错,这个函数在返回时没有delete释放动态创建的内存。这种情况下大概是“忘记了“吧。那么 再看这个例子:
void remodel(std::string & str)
{
std::string * ps = new std::string(str);
...
if(weird_thing())
throw exeption() //抛出异常
str = ps;
delete ps;
return;
}
你可能会想为什么不在抛出异常之前就delete?可以,没有问题,但是这不是长久之计,为什么?because 如果你忘了呢?在大的项目中如果忘记释放将可能带来严重后果,不能只靠记忆性delete来释放内存。
因此C++11引入新的指针来避免忘记释放的问题:智能指针.
介绍三个智能指针模板(auto_ptr、unique_ptr、shared_ptr):
所有的智能指针的使用都是要包含头文件<memory.h>
一、auto_ptr
那么例子将会之这样:
void remodel(std::string & str)
{
auto_ptr<std::string>ps(new std::string(str));
...
if(weird_thing())
throw exeption() //抛出异常
str = *ps;
return;
}
这样就不用使用delete了,他将自动的释放掉动态创建的内存。
这些智能指针模板都是位于名称空间std中,
但是为什么C++摒弃了auto_ptr呢?
像这样:
auto_ptr<string>films[1] = {auto_ptr<string>(new string("Fowl Balls"))};
auto_ptr<string>pwin;
pwin = films[0]; //将所有权转移给了pwin
cout << *fims[0] << endl; //这样做会报错
上面例子表明auto_ptr是由所有权(所有人依法对自己财产所享有的占有,使用,收益和处分的权利)模型的,当一个auto_ptr将自己赋值给另一个智能指针后,自己所有东西就赋予了被赋值的指针。自己就无权访问任何信息。(PS:反正我是这么理解的)(所有权被剥夺,这是件好事,可以防止两个析构函数视图删除一个对象)
所以C++摒弃了它(因为使用它后不能将两个指针指向同一个对象(地址))。
将auto_ptr写成shared_ptr就可以正常运行!
二、unique_ptr
可以说unique_ptr就是auto_ptr的升级版智能指针,它依然也是有所有权模型的,同样上述例子它依然是报错的,但是它会在编译器阶段报错,这是很不错的,至少比起在运行阶段。
unique_ptr是安全的可靠地
总之,党程序试图将一个 unique_ptr 赋值给另一个时,如果源 unique_ptr 是个临时右值,编译器允许这么做;如果源 unique_ptr 将存在一段时间,编译器将禁止这么做
三、shared_ptr
shared_ptr 是一个标准的共享所有权的智能指针, 允许多个指针指向同一个对象. 定义在 memory 文件中(非memory.h), 命名空间为 std.
shared_ptr 是为了解决 auto_ptr 在对象所有权上的局限性(auto_ptr 是独占的), 在使用引用计数的机制上提供了可以共享所有权的智能指针, 当然这需要额外的开销:
(1) shared_ptr 对象除了包括一个所拥有对象的指针外, 还必须包括一个引用计数代理对象的指针.
(2) 时间上的开销主要在初始化和拷贝操作上, *和->操作符重载的开销跟auto_ptr是一样.
(3) 开销并不是我们不使用shared_ptr的理由, 永远不要进行不成熟的优化, 直到性能分析器告诉你这一点.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
最重要的要记住:
使用new 分配内存时,才能使用auto_ptr和shared_ptr,使用new[ ]分配内存时,不能使用它们。不使用new分配内存时,不能使用auto_ptr或者shared_ptr;不适用new或new[ ]分配内存时,不能使用unique_ptr。