Answers:
当您具有可以分配每个智能指针的属性时,这很容易。有三个重要属性。
第一种意味着智能指针不能删除对象,因为它不拥有它。第二个意味着仅一个智能指针可以同时指向同一对象。例如,如果要从函数返回智能指针,则将所有权转移到返回的智能指针。
第三种意味着多个智能指针可以同时指向同一对象。这也适用于原始指针,但是原始指针缺乏重要的功能:它们不定义它们是否拥有。如果每个所有者放弃对象,则所有权共享智能指针将删除该对象。经常需要执行此操作,因此共享拥有的智能指针得到了广泛传播。
一些拥有的智能指针既不支持第二个也不支持第三个。因此,它们不能从函数返回或传递到其他地方。这最适合于RAII
将智能指针保留在本地且仅在创建后将其移出范围后释放对象的目的。
所有权共享可以通过使用副本构造函数来实现。这自然会复制一个智能指针,并且副本和原始对象都将引用同一对象。所有权转移目前无法真正在C ++中实现,因为没有办法将某种东西从一个对象转移到该语言支持的另一个对象:如果尝试从函数返回一个对象,那么实际上是在复制对象。因此,实现所有权转移的智能指针必须使用复制构造函数来实现所有权转移。但是,这又反过来破坏了其在容器中的用法,因为需求说明了容器元素的复制构造函数的某种行为,该行为与这些智能指针的所谓“移动构造函数”行为不兼容。
C ++ 1x通过引入所谓的“移动构造函数”和“移动赋值运算符”,为所有权转让提供了本机支持。它还带有称为的所有权转移智能指针unique_ptr
。
scoped_ptr
是既不可转让也不可共享的智能指针。如果您在本地需要分配内存,它只是可用的,但是请确保在超出范围时再次将其释放。但是,如果您愿意,它仍然可以与另一个scoped_ptr交换。
shared_ptr
是共享所有权(以上第三种)的智能指针。它被引用计数,因此它可以查看其最后一个副本何时超出范围,然后释放所管理的对象。
weak_ptr
是一个没有所有权的智能指针。它用于引用受管理对象(由shared_ptr管理)而无需添加引用计数。通常,您需要从shared_ptr中获取原始指针并进行复制。但这并不安全,因为您将无法检查实际删除对象的时间。因此,weak_ptr通过引用shared_ptr管理的对象来提供方法。如果您需要访问该对象,则可以锁定它的管理(以避免在另一个线程中,shared_ptr在使用该对象时将其释放),然后再使用它。如果weak_ptr指向已删除的对象,它将抛出异常来通知您。当您有循环引用时,使用weak_ptr最为有益:引用计数无法轻松应对这种情况。
intrusive_ptr
就像shared_ptr一样,但是它不会将引用计数保留在shared_ptr中,而是将计数的增加/减少留给了一些需要由被管理对象定义的辅助函数。这样做的好处是可以将已经被引用的对象(其引用计数由外部引用计数机制递增)可以填充到intrusive_ptr中-因为该引用计数不再位于智能指针的内部,而是智能指针使用现有的参考计数机制。
unique_ptr
是所有权指针的转移。您不能复制它,但是可以使用C ++ 1x的move构造函数移动它:
unique_ptr<type> p(new type);
unique_ptr<type> q(p); // not legal!
unique_ptr<type> r(move(p)); // legal. p is now empty, but r owns the object
unique_ptr<type> s(function_returning_a_unique_ptr()); // legal!
这是std :: auto_ptr所遵循的语义,但是由于缺少对移动的本机支持,因此无法为它们提供陷阱。unique_ptr会自动从临时的其他unique_ptr中窃取资源,这是移动语义的关键特征之一。auto_ptr在下一个C ++ Standard版本中将不推荐使用,而推荐使用unique_ptr。C ++ 1x还允许填充只能移动但不能复制到容器中的对象。因此,您可以将unique_ptr填充到一个向量中。如果您想了解更多有关此内容的信息,我将在这里停止,并为您提供一篇不错的文章。
auto_ptr
已弃用(C ++ 11)。
intrusive_ptr
与shared_ptr
更好的缓存一致性相比,它更可取。显然,如果将引用计数存储为托管对象本身而不是单独对象的一部分,则缓存的性能会更好。这可以在被管理对象的模板或超类中实现。
scoped_ptr是最简单的。当超出范围时,它将被销毁。以下代码是非法的(scoped_ptrs是不可复制的),但将说明一点:
std::vector< scoped_ptr<T> > tPtrVec;
{
scoped_ptr<T> tPtr(new T());
tPtrVec.push_back(tPtr);
// raw T* is freed
}
tPtrVec[0]->DoSomething(); // accessing freed memory
shared_ptr被引用计数。每次进行复制或分配时,参考计数都会增加。每次触发实例的析构函数时,原始T *的引用计数都会减少。一旦为0,则释放指针。
std::vector< shared_ptr<T> > tPtrVec;
{
shared_ptr<T> tPtr(new T());
// This copy to tPtrVec.push_back and ultimately to the vector storage
// causes the reference count to go from 1->2
tPtrVec.push_back(tPtr);
// num references to T goes from 2->1 on the destruction of tPtr
}
tPtrVec[0]->DoSomething(); // raw T* still exists, so this is safe
weak_ptr是对共享指针的弱引用,它要求您检查指向的shared_ptr是否仍然存在
std::vector< weak_ptr<T> > tPtrVec;
{
shared_ptr<T> tPtr(new T());
tPtrVec.push_back(tPtr);
// num references to T goes from 1->0
}
shared_ptr<T> tPtrAccessed = tPtrVec[0].lock();
if (tPtrAccessed[0].get() == 0)
{
cout << "Raw T* was freed, can't access it"
}
else
{
tPtrVec[0]->DoSomething(); // raw
}
intrusive_ptr通常在必须使用第三者智能ptr时使用。它将调用一个免费函数来增加和减少引用计数。有关更多信息,请参阅boost文档的链接。
if (tPtrAccessed[0].get() == 0)
假设是if (tPtrAccessed.get() == 0)
?
boost::ptr_container
在任何有关增强智能指针的调查中都不要忽略。在例如std::vector<boost::shared_ptr<T> >
太慢的情况下,它们可能是无价的。
我赞同有关查看文档的建议。它并没有看起来那么可怕。和一些简短的提示:
scoped_ptr
-指针超出范围时会自动删除。注意-无法分配,但不会产生开销intrusive_ptr
-引用计数指针,无开销smart_ptr
。但是对象本身存储引用计数weak_ptr
-与shared_ptr
一起处理导致循环依赖的情况(请阅读文档,并在google上搜索漂亮的图片;)shared_ptr
-通用,最强大(最重量级)的智能指针(来自boost提供的指针)auto_ptr
,可确保当控件离开作用域时,它指向的对象会自动销毁。但是,它具有与其他人不同的复制语义。unique_ptr
- 将随C ++ 0x一起提供回复编辑: 是