C++ 智能指针(提升)解释

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/569775/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 15:59:33  来源:igfitidea点击:

smart pointers (boost) explained

c++boostsmart-pointers

提问by Johannes Schaub - litb

What is the difference between the following set of pointers? When do you use each pointer in production code, if at all?

下面这组指针有什么区别?你什么时候在生产代码中使用每个指针,如果有的话?

Examples would be appreciated!

示例将不胜感激!

  1. scoped_ptr

  2. shared_ptr

  3. weak_ptr

  4. intrusive_ptr

  1. scoped_ptr

  2. shared_ptr

  3. weak_ptr

  4. intrusive_ptr

Do you use boost in production code?

你在生产代码中使用 boost 吗?

回答by Johannes Schaub - litb

Basic properties of smart pointers

智能指针的基本属性

It's easy when you have properties that you can assign each smart pointer. There are three important properties.

当您拥有可以分配每个智能指针的属性时,这很容易。有三个重要的属性。

  • no ownership at all
  • transfer of ownership
  • share of ownership
  • 根本没有所有权
  • 所有权转让
  • 所有权份额

The first means that a smart pointer cannot delete the object, because it doesn't own it. The second means that only one smart pointer can ever point to the same object at the same time. If the smart pointer is to be returned from functions, the ownership is transferred to the returned smart pointer, for example.

第一个意思是智能指针不能删除对象,因为它不拥有它。第二种意味着只有一个智能指针可以同时指向同一个对象。例如,如果要从函数返回智能指针,则所有权将转移到返回的智能指针。

The third means that multiple smart pointers can point to the same object at the same time. This applies to a raw pointertoo, however raw pointers lack an important feature: They do not define whether they are owningor not. A share of ownership smart pointer will delete the object if every owner gives up the object. This behavior happens to be needed often, so shared owning smart pointers are widely spread.

第三个意思是多个智能指针可以同时指向同一个对象。这也适用于原始指针,但是原始指针缺少一个重要的特性:它们没有定义它们是否拥有。如果每个所有者都放弃该对象,则所有权共享智能指针将删除该对象。这种行为恰好经常需要,因此共享拥有智能指针被广泛传播。

Some owning smart pointers support neither the second nor the third. They can therefore not be returned from functions or passed somewhere else. Which is most suitable for RAIIpurposes where the smart pointer is kept local and is just created so it frees an object after it goes out of scope.

一些拥有智能指针既不支持第二个也不支持第三个。因此它们不能从函数返回或传递到其他地方。这最适合RAII将智能指针保存在本地并且刚刚创建以便在超出范围后释放对象的目的。

Share of ownership can be implemented by having a copy constructor. This naturally copies a smart pointer and both the copy and the original will reference the same object. Transfer of ownership cannot really be implemented in C++ currently, because there are no means to transfer something from one object to another supported by the language: If you try to return an object from a function, what is happening is that the object is copied. So a smart pointer that implements transfer of ownership has to use the copy constructor to implement that transfer of ownership. However, this in turn breaks its usage in containers, because requirements state a certain behavior of the copy constructor of elements of containers which is incompatible with this so-called "moving constructor" behavior of these smart pointers.

所有权共享可以通过复制构造函数来实现。这自然会复制一个智能指针,并且副本和原始指针都将引用同一个对象。所有权的转移目前无法在 C++ 中真正实现,因为没有办法将某些东西从一个对象转移到该语言支持的另一个对象:如果您尝试从函数返回一个对象,发生的情况是该对象被复制。因此,实现所有权转移的智能指针必须使用复制构造函数来实现所有权转移。然而,这反过来又破坏了它在容器中的使用,因为需求声明了容器元素的复制构造函数的某些行为,这与这些智能指针的这种所谓的“移动构造函数”行为不兼容。

C++1x provides native support for transfer-of-ownership by introducing so-called "move constructors" and "move assignment operators". It also comes with such a transfer-of-ownership smart pointer called unique_ptr.

C++1x 通过引入所谓的“移动构造函数”和“移动赋值运算符”为所有权转移提供了本机支持。它还带有这样一个名为unique_ptr.

Categorizing smart pointers

分类智能指针

scoped_ptris a smart pointer that is neither transferable nor sharable. It's just usable if you locally need to allocate memory, but be sure it's freed again when it goes out of scope. But it can still be swapped with another scoped_ptr, if you wish to do so.

scoped_ptr是一个既不可转让也不可共享的智能指针。如果您需要在本地分配内存,则它仅可用,但请确保在超出范围时再次释放它。但如果您愿意,它仍然可以与另一个 scoped_ptr 交换。

shared_ptris a smart pointer that shares ownership (third kind above). It is reference counted so it can see when the last copy of it goes out of scope and then it frees the object managed.

shared_ptr是一个共享所有权的智能指针(上面的第三种)。它是引用计数的,因此它可以看到它的最后一个副本何时超出范围,然后释放所管理的对象。

weak_ptris a non-owning smart pointer. It is used to reference a managed object (managed by a shared_ptr) without adding a reference count. Normally, you would need to get the raw pointer out of the shared_ptr and copy that around. But that would not be safe, as you would not have a way to check when the object was actually deleted. So, weak_ptr provides means by referencing an object managed by shared_ptr. If you need to access the object, you can lock the management of it (to avoid that in another thread a shared_ptr frees it while you use the object) and then use it. If the weak_ptr points to an object already deleted, it will notice you by throwing an exception. Using weak_ptr is most beneficial when you have a cyclic reference: Reference counting cannot easily cope with such a situation.

weak_ptr是一个非拥有的智能指针。它用于在不添加引用计数的情况下引用托管对象(由 shared_ptr 管理)。通常,您需要从 shared_ptr 中获取原始指针并将其复制。但这并不安全,因为您无法检查对象何时被实际删除。因此,weak_ptr 通过引用由 shared_ptr 管理的对象来提供方法。如果您需要访问该对象,您可以锁定它的管理(以避免在另一个线程中使用该对象时 shared_ptr 释放它)然后使用它。如果weak_ptr 指向一个已经被删除的对象,它会通过抛出异常来通知你。当你有一个循环引用时,使用 weak_ptr 是最有益的:引用计数不能轻易应对这种情况。

intrusive_ptris like a shared_ptr but it does not keep the reference count in a shared_ptr but leaves incrementing/decrementing the count to some helper functions that need to be defined by the object that is managed. This has the advantage that an already referenced object (which has a reference count incremented by an external reference counting mechanism) can be stuffed into an intrusive_ptr - because the reference count is not anymore internal to the smart pointer, but the smart pointer uses an existing reference counting mechanism.

intrusive_ptr就像一个 shared_ptr 但它不会将引用计数保留在 shared_ptr 中,而是将计数的递增/递减留给一些需要由管理的对象定义的辅助函数。这样做的好处是可以将已经被引用的对象(其引用计数由外部引用计数机制递增)填充到 intrusive_ptr 中 - 因为引用计数不再是智能指针的内部,但智能指针使用现有的引用计数机制。

unique_ptris a transfer of ownership pointer. You cannot copy it, but you can move it by using C++1x's move constructors:

unique_ptr是所有权的转移指针。你不能复制它,但你可以使用 C++1x 的移动构造函数移动它:

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!

This is the semantic that std::auto_ptr obeys, but because of missing native support for moving, it fails to provide them without pitfalls. unique_ptr will automatically steal resources from a temporary other unique_ptr which is one of the key features of move semantics. auto_ptr will be deprecated in the next C++ Standard release in favor of unique_ptr. C++1x will also allow stuffing objects that are only movable but not copyable into containers. So you can stuff unique_ptr's into a vector for example. I'll stop here and reference you to a fine articleabout this if you want to read more about this.

这是 std::auto_ptr 遵循的语义,但由于缺少对移动的原生支持,它无法毫无缺陷地提供它们。unique_ptr 将自动从临时的其他 unique_ptr 中窃取资源,这是移动语义的关键特征之一。auto_ptr 将在下一个 C++ 标准版本中被弃用,以支持 unique_ptr。C++1x 还允许填充只能移动但不能复制到容器中的对象。因此,您可以将 unique_ptr 填充到向量中。如果您想阅读更多关于此的内容,我将在此停止并为您提供有关此内容的精彩文章

回答by Doug T.

scoped_ptris the simplest. When it goes out of scope, it is destroyed. The following code is illegal (scoped_ptrs are non-copyable) but will illustrate a point:

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_ptris reference counted. Every time a copy or assignment occurs, the reference count is incremented. Every time an instance's destructor is fired, the reference count for the raw T* is decremented. Once it is 0, the pointer is freed.

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_ptris a weak-reference to a shared pointer that requires you to check to see if the pointed-to shared_ptr is still around

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_ptris typically used when there is a 3rd party smart ptr you must use. It will call a free function to add and decrement the reference count.See the linkto boost documentation for more info.

当您必须使用第 3 方智能 ptr 时,通常会使用intrusive_ptr。它将调用一个免费函数来添加和减少引用计数。有关更多信息,请参阅boost 文档的链接

回答by timday

Don't overlook boost::ptr_containerin any survey of boost smart pointers. They can be invaluable in situations where a e.g std::vector<boost::shared_ptr<T> >would be too slow.

boost::ptr_container在任何有关 boost 智能指针的调查中都不要忽视。在 egstd::vector<boost::shared_ptr<T> >太慢的情况下,它们可能是无价的。

回答by Anonymous

I second the advice about looking at the documentation. It is not as scary as it seems. And few short hints:

我支持有关查看文档的建议。它并不像看起来那么可怕。还有一些简短的提示:

  • scoped_ptr- a pointer automatically deleted when it goes out of scope. Note - no assignment possible, but introduces no overhead
  • intrusive_ptr- reference counting pointer with no overhead of smart_ptr. However the object itself stores the reference count
  • weak_ptr- works together with shared_ptrto deal with the situations resulting in circular dependencies (read the documentation, and search on google for nice picture ;)
  • shared_ptr- the generic, most powerful (and heavyweight) of the smart pointers (from the ones offered by boost)
  • There is also old auto_ptr, that ensures that the object to which it points gets destroyed automatically when control leaves a scope. However it has different copy semantics than the rest of the guys.
  • unique_ptr- will come with C++0x
  • scoped_ptr- 超出范围时自动删除的指针。注意 - 不可能分配,但不会引入开销
  • intrusive_ptr- 没有开销的引用计数指针smart_ptr。但是对象本身存储引用计数
  • weak_ptr- 一起shared_ptr处理导致循环依赖的情况(阅读文档,并在谷歌上搜索漂亮的图片;)
  • shared_ptr- 通用的、最强大(和重量级)的智能指针(来自 boost 提供的指针)
  • 还有 old auto_ptr,确保它指向的对象在控制离开作用域时自动销毁。然而,它具有与其他人不同的复制语义。
  • unique_ptr-将带有 C++0x

Response to edit:Yes

对编辑的回应: