C++ 智能指针:谁拥有对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/94227/
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 12:48:48  来源:igfitidea点击:

Smart pointers: who owns the object?

c++memory-managementsmart-pointersownership-semantics

提问by Martin York

C++ is all about memory ownership - aka ownership semantics.

C++ 是关于内存所有权的——也就是所有权语义

It is the responsibility of the owner of a chunk of dynamically allocated memory to release that memory. So the question really becomes who owns the memory.

释放该内存是动态分配内存块的所有者的责任。所以问题真的变成了谁拥有内存。

In C++ ownership is documented by the type a rawpointer is wrapped inside thus in a good (IMO) C++ program it is very rare (rare, not never) to see raw pointers passed around (as raw pointers have no inferred ownership thus we can not tell who owns the memory and thus without careful reading of the documentation you can't tell who is responsible for ownership).

在 C++ 中,所有权由原始指针包裹在其中的类型记录,因此在一个好的(IMO)C++ 程序中,看到传递的原始指针是非常罕见的(很少见,不是从来没有)(因为原始指针没有推断的所有权,因此我们可以不知道谁拥有内存,因此如果不仔细阅读文档,您就无法判断谁对所有权负责)。

Conversely, it is rare to see raw pointers stored in a class each raw pointer is stored within its own smart pointer wrapper. (N.B.:If you don't own an object you should not be storing it because you can not know when it will go out of scope and be destroyed.)

相反,很少看到原始指针存储在类中,每个原始指针都存储在其自己的智能指针包装器中。(注意:如果你不拥有一个对象,你不应该存储它,因为你不知道它什么时候会超出范围并被销毁。)

So the question:

所以问题是:

  • What type of ownership semantic have people come across?
  • What standard classes are used to implement those semantics?
  • In what situations do you find them useful?
  • 人们遇到过什么类型的所有权语义?
  • 哪些标准类用于实现这些语义?
  • 在什么情况下你觉得它们有用?

Lets keep 1 type of semantic ownership per answer so they can be voted up and down individually.

让我们为每个答案保留 1 种语义所有权,以便可以单独投票赞成和反对。

Summary:

概括:

Conceptually, smart pointers are simple and a naive implementation is easy. I have seen many attempted implementations, but invariably they are broken in some way that is not obvious to casual use and examples. Thus I recommend always using well tested smart pointers from a library rather than rolling your own. std::auto_ptror one of the Boost smart pointers seem to cover all my needs.

从概念上讲,智能指针很简单,简单的实现也很容易。我见过许多尝试过的实现,但它们总是以某种对于随意使用和示例来说并不明显的方式被破坏。因此,我建议始终使用库中经过良好测试的智能指针,而不是使用自己的智能指针。std::auto_ptr或者 Boost 智能指针之一似乎可以满足我的所有需求。

std::auto_ptr<T>:

std::auto_ptr<T>

Single person owns the object. Transfer of ownership is allowed.

单身人士拥有该对象。允许转让所有权。

Usage: This allows you to define interfaces that show the explicit transfer of ownership.

用法:这允许您定义显示所有权显式转移的接口。

boost::scoped_ptr<T>

boost::scoped_ptr<T>

Single person owns the object. Transfer of ownership is NOT allowed.

单身人士拥有该对象。不允许转让所有权。

Usage: Used to show explicit ownership. Object will be destroyed by destructor or when explicitly reset.

用法:用于显示明确的所有权。对象将被析构函数或显式重置时销毁。

boost::shared_ptr<T>(std::tr1::shared_ptr<T>)

boost::shared_ptr<T>( std::tr1::shared_ptr<T>)

Multiple ownership. This is a simple reference counted pointer. When the reference count reaches zero, the object is destroyed.

多重所有权。这是一个简单的引用计数指针。当引用计数达到零时,对象被销毁。

Usage: When an object can have multiple owers with a lifetime that can not be determined at compile time.

用法:当一个对象可以有多个生命周期无法在编译时确定的情况时。

boost::weak_ptr<T>:

boost::weak_ptr<T>

Used with shared_ptr<T>in situations where a cycle of pointers may happen.

使用shared_ptr<T>的情况下指针的循环可能发生。

Usage: Used to stop cycles from retaining objects when only the cycle is maintaining a shared refcount.

用法:用于在只有循环维护共享引用计数时停止循环保留对象。

采纳答案by Fabio Ceconello

For me, these 3 kinds cover most of my needs:

对我来说,这 3 种满足了我的大部分需求:

shared_ptr- reference-counted, deallocation when the counter reaches zero

shared_ptr- 引用计数,当计数器达到零时重新分配

weak_ptr- same as above, but it's a 'slave' for a shared_ptr, can't deallocate

weak_ptr- 同上,但它是 a 的“奴隶” shared_ptr,不能解除分配

auto_ptr- when the creation and deallocation happen inside the same function, or when the object has to be considered one-owner-only ever. When you assign one pointer to another, the second 'steals' the object from the first.

auto_ptr- 当创建和释放发生在同一个函数中时,或者当对象必须被视为一个所有者时。当您将一个指针分配给另一个指针时,第二个“窃取”第一个的对象。

I have my own implementation for these, but they are also available in Boost.

我对这些有自己的实现,但它们也可以在Boost.

I still pass objects by reference (constwhenever possible), in this case the called method must assume the object is alive only during the time of call.

我仍然通过引用传递对象(const只要有可能),在这种情况下,被调用的方法必须假设对象仅在调用期间处于活动状态。

There's another kind of pointer that I use that I call hub_ptr. It's when you have an object that must be accessible from objects nested in it (usually as a virtual base class). This could be solved by passing a weak_ptrto them, but it doesn't have a shared_ptrto itself. As it knows these objects wouldn't live longer than him, it passes a hub_ptr to them (it's just a template wrapper to a regular pointer).

我使用另一种指针,我称之为hub_ptr。当您有一个对象必须可以从嵌套在其中的对象(通常作为虚拟基类)访问时。这可以通过将 a 传递weak_ptr给他们来解决,但它本身没有 a shared_ptr。因为它知道这些对象的寿命不会比他长,所以它会将一个 hub_ptr 传递给它们(它只是一个常规指针的模板包装器)。

回答by paercebal

Simple C++ Model

简单的 C++ 模型

In most modules I saw, by default, it was assumed that receiving pointers was notreceiving ownership. In fact, functions/methods abandoning ownership of a pointer were both very rare and explicitly expressed that fact in their documentation.

在我看到的大多数模块中,默认情况下,假设接收指针没有接收所有权。事实上,放弃指针所有权的函数/方法非常罕见,并且在他们的文档中明确表达了这一事实。

This model assumes that the user is owner only of what he/she explicitly allocates. Everything else is automatically disposed of (at scope exit, or through RAII). This is a C-like model, extended by the fact most pointers are owned by objects that will deallocate them automatically or when needed (at said objects destruction, mostly), and that the life duration of objects are predictable (RAII is your friend, again).

该模型假定用户仅是他/她明确分配的内容的所有者。其他所有内容都会自动处理(在范围出口处,或通过 RAII)。这是一个类似 C 的模型,由于大多数指针由对象拥有,这些对象将自动或在需要时(大多数情况下在所述对象销毁时)释放它们,并且对象的生命周期是可预测的(RAII 是您的朋友,再次)。

In this model, raw pointers are freely circulating and mostly not dangerous (but if the developer is smart enough, he/she will use references instead whenever possible).

在这个模型中,原始指针是自由循环的,而且大多没有危险(但如果开发人员足够聪明,他/她会尽可能使用引用)。

  • raw pointers
  • std::auto_ptr
  • boost::scoped_ptr
  • 原始指针
  • std::auto_ptr
  • boost::scoped_ptr

Smart Pointed C++ Model

智能尖头 C++ 模型

In a code full of smart pointers, the user can hope to ignore the lifetime of objects. The owner is never the user code: It is the smart pointer itself (RAII, again). The problem is that circular references mixed with reference counted smart pointers can be deadly, so you have to deal both with both shared pointers and weak pointers. So you have still ownership to consider (the weak pointer could well point to nothing, even if its advantage over raw pointer is that it can tell you so).

在充满智能指针的代码中,用户可以希望忽略对象的生命周期。所有者永远不是用户代码:它是智能指针本身(再次是 RAII)。问题是循环引用与引用计数智能指针混合可能是致命的,因此您必须同时处理共享指针和弱指针。所以你仍然需要考虑所有权(弱指针很可能不指向任何东西,即使它比原始指针的优势在于它可以告诉你)。

  • boost::shared_ptr
  • boost::weak_ptr
  • boost::shared_ptr
  • boost::weak_ptr

Conclusion

结论

No matter the models I describe, unless exception, receiving a pointer is notreceiving its ownershipand it is still very important to know who owns who. Even for C++ code heavily using references and/or smart pointers.

不管我描述的模型是什么,除非例外,接收一个指针并不是接收它的所有权知道谁拥有谁仍然非常重要。即使对于大量使用引用和/或智能指针的 C++ 代码。

回答by MSN

Don't have shared ownership. If you do, make sure it's only with code you don't control.

没有共享所有权。如果这样做,请确保它仅使用您无法控制的代码。

That solves 100% of the problems, since it forces you to understand how everything interacts.

这解决了 100% 的问题,因为它迫使您了解一切如何相互作用。

回答by Ryan Ginstrom

From boost, there's also the pointer containerlibrary. These are a bit more efficient and easier to use than a standard container of smart pointers, if you'll only be using the objects in the context of their container.

在 boost 中,还有指针容器库。如果您只在其容器的上下文中使用对象,那么它们比标准的智能指针容器更高效且更易于使用。

On Windows, there are the COM pointers (IUnknown, IDispatch, and friends), and various smart pointers for handling them (e.g. the ATL's CComPtrand the smart pointers auto-generated by the "import" statement in Visual Studio based on the _com_ptrclass).

在 Windows 上,有 COM 指针(IUnknown、IDispatch 和朋友),以及用于处理它们的各种智能指针(例如 ATL 的CComPtr和基于_com_ptr类的Visual Studio 中的“import”语句自动生成的智能指针)。

回答by Martin York

  • Shared Ownership
  • boost::shared_ptr
  • 共享所有权
  • boost::shared_ptr

When a resource is shared between multiple objects. The boost shared_ptr uses reference counting to make sure the resource is de-allocated when everybody is finsihed.

当一个资源在多个对象之间共享时。boost shared_ptr 使用引用计数来确保在每个人都完成时取消分配资源。

回答by Matt Cruikshank

std::tr1::shared_ptr<Blah>is quite often your best bet.

std::tr1::shared_ptr<Blah>通常是您最好的选择。

回答by Pieter

  • One Owner
  • boost::scoped_ptr
  • 一位业主
  • boost::scoped_ptr

When you need to allocate memory dynamically but want to be sure it gets deallocated on every exit point of the block.

当您需要动态分配内存但希望确保它在块的每个退出点上都被释放时。

I find this usefull as it can easily be reseated, and released without ever having to worry about a leak

我发现这很有用,因为它可以很容易地重新安装和释放,而不必担心泄漏

回答by Nemanja Trifunovic

I don't think I ever was in a position to have shared ownership in my design. In fact, from the top of my head the only valid case I can think of is Flyweight pattern.

我认为我从来没有能够在我的设计中共享所有权。事实上,在我的脑海中,我能想到的唯一有效案例是享元模式。

回答by Hernán

yasper::ptr is a lightweight, boost::shared_ptr like alternative. It works well in my (for now) small project.

yasper::ptr 是一个轻量级的,类似于 boost::shared_ptr 的替代品。它在我(目前)的小项目中运行良好。

In the web page at http://yasper.sourceforge.net/it's described as follows:

http://yasper.sourceforge.net/的网页中,它的描述如下:

Why write another C++ smart pointer? There already exist several high quality smart pointer implementations for C++, most prominently the Boost pointer pantheon and Loki's SmartPtr. For a good comparison of smart pointer implementations and when their use is appropriate please read Herb Sutter's The New C++: Smart(er) Pointers. In contrast with the expansive features of other libraries, Yasper is a narrowly focused reference counting pointer. It corresponds closely with Boost's shared_ptr and Loki's RefCounted/AllowConversion policies. Yasper allows C++ programmers to forget about memory management without introducing the Boost's large dependencies or having to learn about Loki's complicated policy templates. Philosophy

* small (contained in single header)
* simple (nothing fancy in the code, easy to understand)
* maximum compatibility (drop in replacement for dumb pointers)

The last point can be dangerous, since yasper permits risky (yet useful) actions (such as assignment to raw pointers and manual release) disallowed by other implementations. Be careful, only use those features if you know what you're doing!

为什么要编写另一个 C++ 智能指针?已经存在几个高质量的 C++ 智能指针实现,最突出的是 Boost 指针万神殿和 Loki 的 SmartPtr。为了更好地比较智能指针的实现以及何时使用它们是合适的,请阅读 Herb Sutter 的 The New C++: Smart(er) Pointers。与其他库的扩展特性相比,Yasper 是一个狭隘的引用计数指针。它与 Boost 的 shared_ptr 和 Loki 的 RefCounted/AllowConversion 策略密切对应。Yasper 允许 C++ 程序员忘记内存管理,而无需引入 Boost 的大量依赖项,也无需了解 Loki 的复杂策略模板。哲学

* small (contained in single header)
* simple (nothing fancy in the code, easy to understand)
* maximum compatibility (drop in replacement for dumb pointers)

最后一点可能很危险,因为 yasper 允许其他实现不允许的有风险(但有用)的操作(例如分配给原始指针和手动释放)。小心,只有在您知道自己在做什么时才使用这些功能!

回答by Daniel Earwicker

There is another frequently used form of single-transferable-owner, and it is preferable to auto_ptrbecause it avoids the problems caused by auto_ptr's insane corruption of assignment semantics.

还有另一种经常使用的单一可转让所有者的形式,它更可取,auto_ptr因为它避免了由auto_ptr分配语义的疯狂破坏引起的问题。

I speak of none other than swap. Any type with a suitable swapfunction can be conceived of as a smart referenceto some content, which it owns until such time as ownership is transferred to another instance of the same type, by swapping them. Each instance retains its identity but gets bound to new content. It's like a safely rebindable reference.

我说的就是swap. 任何具有合适swap功能的类型都可以被认为是对某些内容的智能引用,它拥有这些内容,直到所有权通过交换它们转移到同一类型的另一个实例为止。每个实例都保留其身份,但会绑定到新内容。这就像一个安全的可重新绑定的参考。

(It's a smart reference rather than a smart pointer because you don't have to explicitly dereference it to get at the content.)

(这是一个智能引用而不是智能指针,因为您不必显式取消引用它来获取内容。)

This means that auto_ptr becomes less necessary - it's only needed to fill the gaps where types don't have a good swapfunction. But all std containers do.

这意味着 auto_ptr 变得不那么必要了——它只需要填补类型没有良好swap功能的空白。但所有标准容器都可以。