什么是智能指针,何时使用
更新
这个答案相当古老,因此描述了什么是“好的”,这是Boost库提供的智能指针。自C++11以来,标准库提供了足够的智能指针类型,因此您应该支持使用std::unique\u ptr、std::shared\u ptr和std::weak\u ptr
还有std::auto_ptr。它与作用域指针非常相似,只是它还具有“特殊”的危险复制能力,这也意外地转移了所有权。
它在C++11中被弃用,在C++17中被删除,因此您不应该使用它
std::auto\u ptr<;MyObject>;p1(新的MyObject());
标准::自动测试<;MyObject>;p2=p1;//复制和转让所有权。
//p1设置为空!
p2->;DoSomething();//作品
p1->;DoSomething();//噢。希望引发一些空指针异常。
旧答案
智能指针是一个包一个“原始”(或“裸”)C++指针,用来管理指向的对象的生命周期的类。没有单一的智能指针类型,但它们都试图以实用的方式抽象原始指针
智能指针应该优先于原始指针。如果你觉得你需要使用指针(首先考虑一下,如果你真的DO),你通常会想使用一个智能指针,因为这可以减轻很多原始指针的问题,主要是忘记删除对象和泄漏内存。
对于原始指针,当对象不再有用时,程序员必须显式销毁对象
//需要创建对象来实现某些目标
MyObject*ptr=新的MyObject();
ptr->;DoSomething();//以某种方式使用对象
删除ptr;//销毁该对象。完了。
//等等,如果DoSomething()引发异常怎么办。。。?
通过比较,智能指针定义了一个关于何时销毁对象的策略。您仍然需要创建对象,但不必再担心会破坏它
SomeSmartPtr<;MyObject>;ptr(newmyobject());
ptr->;DoSomething();//以某种方式使用对象。
//对象的破坏会发生,具体取决于
//在智能指针类使用的策略上。
//即使使用DoSomething()也会发生破坏
//引发了一个例外
使用中最简单的策略涉及智能指针包装器对象的范围,例如通过boost::scoped_ptr或std::unique_ptr实现
void f()
{
{
std::unique_ptr<;MyObject>;ptr(新MyObject());
ptr->;dosomethingusseve();
}//ptr超出范围--
//MyObject将自动销毁。
//ptr->;Oops();//编译错误:“ptr”未定义
//因为它已经不在范围之内了。
}
请注意,无法复制std::unique_ptr实例。这样可以防止多次(错误地)删除指针。但是,您可以将对它的引用传递给您调用的其他函数
std::unique_ptrs在您希望将对象的生存期绑定到特定的代码块时非常有用,或者如果您将其作为成员数据嵌入到另一个对象中,则另一个对象的生存期。对象存在,直到包含的代码块退出,或者直到包含的对象本身被销毁
更复杂的智能指针策略涉及指针的引用计数。这允许复制指针。当对象的最后一个“引用”被销毁时,该对象将被删除。此策略由boost::shared_ptr和std::shared_ptr实现
void f()
{
typedef std::shared_ptr<;MyObject>;MyObjectPtr;//很好的短别名
MyObjectPtr p1;//为空
{
MyObjectPtr p2(新MyObject());
//现在创建的对象有一个“引用”
p1=p2;//复制指针。
//现在有两个对对象的引用。
}//p2已销毁,只留下一个对该对象的引用。
}//p1被销毁,留下的引用计数为零。
//对象将被删除。
当对象的生存期要复杂得多,并且没有直接绑定到特定代码段或其他对象时,引用计数指针非常有用
引用计数指针有一个缺点-可能会创建悬挂引用:
//在堆上创建智能指针
MyObjectPtr*pp=新的MyObjectPtr(新的MyObject())
//嗯,我们忘了摧毁智能指针,
//正因为如此,物体永远不会被摧毁!
另一种可能性是创建循环引用:
结构所有者{
std::共享\u ptr<;所有者>;其他;
};
标准::共享\u ptr<;业主>;p1(新所有者());
标准::共享\u ptr<;业主>;p2(新所有者());
p1->;其他=p2;//p1引用p2
p2->;其他=p1;//p2引用p1
//哎呀,p1和p2的参考计数永远不会变为零!
//这些东西永远不会被摧毁!
为了解决这个问题,Boost和C++11都定义了一个弱\u ptr来定义对共享\u ptr的弱(未计算)引用