C++ shared_ptr 和 weak_ptr 的区别
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4984381/
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
shared_ptr and weak_ptr differences
提问by venkysmarty
I am reading Scott Meyers "Effective C++" book. It was mentioned that there are tr1::shared_ptr
and tr1::weak_ptr
act like built-in pointers, but they keep track of how many tr1::shared_ptrs
point to an object.
我正在阅读 Scott Meyers 的“Effective C++”一书。有人提到,有tr1::shared_ptr
和tr1::weak_ptr
像内建指针,但他们跟踪有多少tr1::shared_ptrs
指向一个对象。
This is known as reference counting. This works well in preventing resource leaks in acyclic data structures, but if two or more objects contain tr1::shared_ptrs
such that a cycle is formed, the cycle may keep each other's reference count above zero, even when all external pointers to the cycle have been destroyed.
这称为引用计数。这在防止非循环数据结构中的资源泄漏方面很有效,但是如果两个或多个对象包含tr1::shared_ptrs
这样一个循环,则循环可能会将彼此的引用计数保持在零以上,即使所有指向循环的外部指针都已被销毁。
That's where tr1::weak_ptrs
come in.
那就是tr1::weak_ptrs
进来的地方。
My question is how cyclic data structures make the reference count above zero. I kindly request an example C++ program. How is the problem solved by weak_ptrs
? (again, with example please).
我的问题是循环数据结构如何使引用计数高于零。我恳请请求一个示例 C++ 程序。问题是如何解决的weak_ptrs
?(再次,请举例)。
采纳答案by doron
A shared_ptr
wraps a reference counting mechanism around a raw pointer. So for each instance of the shared_ptr
the reference count is increased by one. If two share_ptr
objects refer the eachother they will never get deleted because they will never end up with a reference count of zero.
Ashared_ptr
在原始指针周围包装了一个引用计数机制。所以对于每个实例shared_ptr
的引用计数加一。如果两个share_ptr
对象相互引用,它们将永远不会被删除,因为它们的引用计数永远不会为零。
weak_ptr
points to a shared_ptr
but does not increase its reference count.This means that the underying object can still be deleted even though there is a weak_ptr
reference to it.
weak_ptr
指向 ashared_ptr
但不增加其引用计数。这意味着即使存在对它的引用,底层对象仍然可以被删除weak_ptr
。
The way that this works is that the weak_ptr
can be use to create a shared_ptr
for whenever one wants to use the underlying object. If however the object has already been deleted then an empty instance of a shared_ptr
is returned. Since the reference count on the underlying object is not increased with a weak_ptr
reference, a circular reference will not result in the underlying object not being deleted.
这样做的方式是,只要想要使用底层对象,weak_ptr
就可以使用它来创建shared_ptr
for。然而,如果该对象已被删除,shared_ptr
则返回一个空的 a 实例。由于底层对象的引用计数不会随着weak_ptr
引用的增加而增加,循环引用不会导致底层对象不被删除。
回答by
Let me repeat your question: "My question, how cyclic data structures makes reference count above zero, kindly request to show with example in C++ program. How the problem is solved by weak_ptrs
again with example please."
让我重复您的问题:“我的问题,循环数据结构如何使引用计数高于零,请在 C++ 程序中以示例显示。weak_ptrs
请再次以示例解决问题。”
The problem occurs with C++ code like this (conceptually):
像这样的 C++ 代码会出现问题(概念上):
class A { shared_ptr<B> b; ... };
class B { shared_ptr<A> a; ... };
shared_ptr<A> x(new A); // +1
x->b = new B; // +1
x->b->a = x; // +1
// Ref count of 'x' is 2.
// Ref count of 'x->b' is 1.
// When 'x' leaves the scope, there will be a memory leak:
// 2 is decremented to 1, and so both ref counts will be 1.
// (Memory is deallocated only when ref count drops to 0)
To answer the second part of your question: It is mathematically impossible for reference counting to deal with cycles. Therefore, a weak_ptr
(which is basically just a stripped down version of shared_ptr
) cannotbe used to solve the cycle problem - the programmer is solving the cycle problem.
回答问题的第二部分:引用计数在数学上不可能处理循环。因此, a weak_ptr
(基本上只是 的精简版本shared_ptr
)不能用于解决循环问题——程序员正在解决循环问题。
To solve it, the programmer needs to be aware of the ownershiprelationship among the objects, or needs to invent an ownership relationship if no such ownership exists naturally.
为了解决这个问题,程序员必须知道的所有权的对象,或需求之间的关系,如果没有这种所有权自然的存在是为了创造一个所有权关系。
The above C++ code can be changed so that A owns B:
可以更改上面的 C++ 代码,使 A 拥有 B:
class A { shared_ptr<B> b; ... };
class B { weak_ptr<A> a; ... };
shared_ptr<A> x(new A); // +1
x->b = new B; // +1
x->b->a = x; // No +1 here
// Ref count of 'x' is 1.
// Ref count of 'x->b' is 1.
// When 'x' leaves the scope, its ref count will drop to 0.
// While destroying it, ref count of 'x->b' will drop to 0.
// So both A and B will be deallocated.
A crucial question is: Can weak_ptr
be used in case the programmer cannot tell the ownership relationship and cannot establish any static ownership because of lack of privilege or lack of information?
一个关键的问题是:weak_ptr
如果程序员因为没有特权或信息不足而无法说出所有权关系,无法建立任何静态所有权,可以使用吗?
The answer is: If ownership among objects is unclear, weak_ptr
cannothelp. If there is a cycle, the programmer has to find it and break it. An alternative remedy is to use a programming language with full garbage collection (such as: Java, C#, Go, Haskell), or to use a conservative (=imperfect) garbage collector which works with C/C++ (such as: Boehm GC).
答案是:如果对象之间的所有权不清楚,weak_ptr
则无济于事。如果有一个循环,程序员必须找到它并打破它。另一种补救方法是使用具有完整垃圾收集功能的编程语言(例如:Java、C#、Go、Haskell),或者使用与 C/C++ 配合使用的保守(=不完美)垃圾收集器(例如:Boehm GC) .
回答by newprint
For future readers.
Just want to point out that explanation given by Atom is excellent, here is working code
对于未来的读者。
只是想指出 Atom 给出的解释非常好,这里是工作代码
#include <memory> // and others
using namespace std;
class B; // forward declaration
// for clarity, add explicit destructor to see that they are not called
class A { public: shared_ptr<B> b; ~A() {cout << "~A()" << endl; } };
class B { public: shared_ptr<A> a; ~B() {cout << "~B()" << endl; } };
shared_ptr<A> x(new A); //x->b share_ptr is default initialized
x->b = make_shared<B>(); // you can't do "= new B" on shared_ptr
x->b->a = x;
cout << x.use_count() << endl;
回答by peterDriscoll
Weak pointers just "observe" the managed object; they don't "keep it alive" or affect its lifetime. Unlike shared_ptr
, when the last weak_ptr
goes out of scope or disappears, the pointed-to object can still exist because the weak_ptr
does not affect the lifetime of the object - it has no ownership rights. The weak_ptr
can be used to determine whether the object exists, and to provide a shared_ptr
that can be used to refer to it.
弱指针只是“观察”托管对象;它们不会“让它保持活力”或影响它的寿命。与 不同shared_ptr
,当最后一个weak_ptr
超出范围或消失时,指向的对象仍然可以存在,因为weak_ptr
不影响对象的生命周期 - 它没有所有权。所述weak_ptr
可用于确定对象是否存在,并提供一种shared_ptr
可用于指它。
The definition of weak_ptr
is designed to make it relatively foolproof, so as a result there is very little you can do directly with a weak_ptr
. For example, you can't dereference it; neither operator*
nor operator->
is defined
for a weak_ptr
. You can't access the pointer to the object with it - there is no get()
function. There is a comparison function defined so that you can store weak_ptrs
in an ordered container, but that's all.
的定义weak_ptr
旨在使其相对万无一失,因此您几乎无法直接使用weak_ptr
. 例如,您不能取消引用它;既没有operator*
也没有operator->
为 a 定义weak_ptr
。您无法使用它访问指向对象的指针 - 没有get()
函数。定义了一个比较函数,以便您可以将其存储weak_ptrs
在有序容器中,仅此而已。
回答by Earth Engine
All the above answer are WRONG. weak_ptr
is NOT used to break cyclic references, they have another purpose.
以上所有答案都是错误的。weak_ptr
不用于中断循环引用,它们还有另一个目的。
Basically, if all shared_ptr(s)
were created by make_shared()
or allocate_shared()
calls, you will NEVER need weak_ptr
if you have no resource other than memory to manage. These functions create the shared_ptr
reference counter object with the object itself, and the memory will be freed at the same time.
基本上,如果所有内容shared_ptr(s)
都是由make_shared()
或allocate_shared()
调用创建的,那么weak_ptr
如果除了内存之外没有其他资源需要管理,您将永远不需要。这些函数shared_ptr
用对象本身创建引用计数器对象,同时释放内存。
The only difference between weak_ptr
and shared_ptr
is that the weak_ptr
allows the reference counter object to be kept after the actual object was freed. As a result, if you keep a lot of shared_ptr
in a std::set
the actual objects will occupy a lot of memory if they are big enough. This problem can be solved by using weak_ptr
instead. In this case, you have to ensure the weak_ptr
stored in the container is not expired before using it.
weak_ptr
和之间的唯一区别shared_ptr
是weak_ptr
允许在释放实际对象后保留引用计数器对象。因此,如果您shared_ptr
在 a 中保留大量std::set
对象,如果它们足够大,实际对象将占用大量内存。这个问题可以通过使用weak_ptr
来解决。在这种情况下,您必须确保weak_ptr
容器中存储的内容没有过期才能使用。