C++ 为什么不能从 unique_ptr 构造一个 weak_ptr?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29059343/
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
Why can't a weak_ptr be constructed from a unique_ptr?
提问by adam10603
If I understand correctly, a weak_ptr
doesn't increment the reference count of the managed object, therefore it doesn't represent ownership. It simply lets you access an object, the lifetime of which is managed by someone else.
So I don't really see why a weak_ptr
can't be constructed from a unique_ptr
, but only a shared_ptr
.
如果我理解正确, aweak_ptr
不会增加托管对象的引用计数,因此它不代表所有权。它只是让您访问一个对象,该对象的生命周期由其他人管理。所以我真的不明白为什么 aweak_ptr
不能从 a 构建unique_ptr
,而只能从 a 构建shared_ptr
。
Can someone briefly explain this?
有人可以简要解释一下吗?
采纳答案by David Haim
std::weak_ptr
can't be used unless you convert it to std::shared_ptr
by the means of lock()
. if the standard allowed what you suggest, that means that you need to convert std::weak_ptr to unique in order to use it, violating the uniqueness (or re-inventing std::shared_ptr
)
std::weak_ptr
不能使用,除非您std::shared_ptr
通过lock()
. 如果标准允许您建议的内容,则意味着您需要将 std::weak_ptr 转换为 unique 才能使用它,从而违反了唯一性(或重新发明std::shared_ptr
)
In order to illustrate, look at the two pieces of code:
为了说明,看两段代码:
std::shared_ptr<int> shared = std::make_shared<int>(10);
std::weak_ptr<int> weak(shared);
{
*(weak.lock()) = 20; //OK, the temporary shared_ptr will be destroyed but the pointee-integer still has shared to keep it alive
}
Now with your suggestion:
现在根据您的建议:
std::unique_ptr<int> unique = std::make_unique<int>(10);
std::weak_ptr<int> weak(unique);
{
*(weak.lock()) = 20; //not OK. the temporary unique_ptr will be destroyed but unique still points at it!
}
That has been said, you may suggest that there is only one unique_ptr
, and you still can dereference weak_ptr
(without creating another unique_ptr
) then there is no problem. But then what is the difference between unique_ptr
and shared_ptr
with one reference? or moreover, what is the difference between a regular unique_ptr
and C-pointers an get by using get
?
话虽如此,您可能会建议只有一个unique_ptr
,并且您仍然可以取消引用weak_ptr
(而不创建另一个unique_ptr
),那么就没有问题。但是,一个参考unique_ptr
和shared_ptr
一个参考之间有什么区别?或者,unique_ptr
使用 get的常规指针和 C 指针之间有什么区别get
?
weak_ptr
is not for "general nonowning resources", it has a very specific job - The main goal of weak_ptr
is to prevent circular pointing of shared_ptr
which will make a memory leak. Anything else needs to be done with plain unique_ptr
and shared_ptr
.
weak_ptr
不是“一般的非拥有资源”,它有一个非常具体的工作 - 主要目标weak_ptr
是防止循环指向shared_ptr
会导致内存泄漏。其他任何事情都需要使用普通unique_ptr
和来完成shared_ptr
。
回答by David Schwartz
If you think about it, a weak_ptr
must refer to something other than the object itself. That's because the object can cease to exist (when there are no more strong pointers to it) and the weak_ptr
still has to refer to something that contains the information that the object no longer exists.
如果您考虑一下,aweak_ptr
必须指代对象本身以外的其他东西。那是因为对象可能不复存在(当没有更多强指针指向它时)并且weak_ptr
仍然必须引用包含对象不再存在的信息的东西。
With a shared_ptr
, that something is the thing that contains the reference count. But with a unique_ptr
, there is no reference count, so there is no thing that contains the reference count, thus nothing to continue to exist when the object is gone. So there's nothing for a weak_ptr
to refer to.
使用 a shared_ptr
,那东西就是包含引用计数的东西。但是对于 a unique_ptr
,没有引用计数,所以没有包含引用计数的东西,因此当对象消失时没有任何东西继续存在。所以没有什么weak_ptr
可以参考的。
There would also be no sane way to use such a weak_ptr
. To use it, you'd have to have some way to guarantee that the object wasn't destroyed while you were using it. That's easy with a shared_ptr
-- that's what a shared_ptr
does. But how do you do that with a unique_ptr
? You obviously can't have two of them, and something else must already own the object or it would have been destroyed since your pointer is weak.
也没有理智的方法来使用这样的weak_ptr
. 要使用它,您必须有某种方法来保证在使用它时对象不会被破坏。使用 a 很容易shared_ptr
——这就是 a 的shared_ptr
作用。但是你如何用 a 做到这一点unique_ptr
?您显然不能拥有其中的两个,并且其他东西必须已经拥有该对象,否则由于您的指针很弱,它会被销毁。
回答by Motti
A shared_ptr
basically has two parts:
Ashared_ptr
基本上有两个部分:
- the pointed-to object
- the reference count object
- 指向的对象
- 引用计数对象
Once the reference count drops to zero the object (#1) is deleted.
一旦引用计数下降到零,对象 (#1) 就会被删除。
Now a weak_ptr
needs to be able to know if an object still exists. In order to do this it has to be able to see the reference count object (#2) if it's not zero it can create a shared_ptr
for the object (by incrementing the reference count). If the count is zero it will return an empty shared_ptr
.
现在 aweak_ptr
需要能够知道对象是否仍然存在。为了做到这一点,它必须能够看到引用计数对象(#2),如果它不为零,它可以shared_ptr
为该对象创建一个(通过增加引用计数)。如果计数为零,它将返回一个空的shared_ptr
。
Now consider when the reference count object (#2) can be deleted? We must wait till no shared_ptr
OR weak_ptr
object refer to it. For this purpose the reference count object holds tworeference counts, a strongref and a weakref. The reference count object will only be deleted when both its counts are zero. This means that part of the memory can only be freed after all the weak references are gone (this implies a hidden disadvantage with make_shared
).
现在考虑何时可以删除引用计数对象(#2)?我们必须等到没有shared_ptr
ORweak_ptr
对象引用它。为此,引用计数对象包含两个引用计数,一个强引用和一个弱引用。引用计数对象只有在其计数都为零时才会被删除。这意味着只有在所有弱引用都消失后才能释放部分内存(这意味着 的隐藏缺点make_shared
)。
tl;dr;weak_ptr
depends on a weak reference countwhich is part of shared_ptr
, there cannot be a weak_ptr
without a shared_ptr
.
tl;博士; weak_ptr
依赖于弱引用计数是部分的shared_ptr
,不能有一个weak_ptr
没有shared_ptr
。
回答by Ulrich Eckhardt
Conceptually, there is nothing preventing an implementation where a weak_ptr only provides access and a unique_ptr controls the lifetime. However, there are problems with that:
从概念上讲,没有什么可以阻止weak_ptr 仅提供访问权限而unique_ptr 控制生命周期的实现。但是,这样做存在以下问题:
unique_ptr
doesn't use reference counting to begin with. Adding the management structure for managing the weak references would be possible, but require an additional dynamic allocation. Sinceunique_ptr
is supposed to avoid any(!) runtime overhead over a raw pointer, that overhead is not acceptable.- In order to use the object referenced by a
weak_ptr
, you need to extract a "real" reference from it, which will first validate that the pointer is not expired first and then give you this real reference (ashared_ptr
in this case). This means that you suddenly have a second reference to an object that is supposed to be uniquely owned, which is a recipe for errors. This can't be fixed by returning a mixed half-strong pointer that only temporarily delays possible destruction of the pointee, because you could just as well store that one, too, defeating the idea behindunique_ptr
.
unique_ptr
不使用引用计数开始。添加用于管理弱引用的管理结构是可能的,但需要额外的动态分配。由于unique_ptr
应该避免原始指针上的任何(!)运行时开销,因此该开销是不可接受的。- 为了使用 a 引用的对象
weak_ptr
,您需要从中提取一个“真实”引用,这将首先验证指针没有过期,然后为您提供这个真实引用(shared_ptr
在这种情况下为 a)。这意味着您突然对一个应该是唯一拥有的对象有了第二个引用,这是错误的一个秘诀。这不能通过返回一个混合的半强指针来解决,该指针只会暂时延迟指针对象的可能破坏,因为您也可以存储该指针,从而击败背后的想法unique_ptr
。
Just wondering, what problem are you trying to solve using a weak_ptr
here?
只是想知道,你想用weak_ptr
这里解决什么问题?
回答by The Paramagnetic Croissant
No-one has mentioned the performance aspect of the problem yet, so let me throw my $0.02 in.
还没有人提到这个问题的性能方面,所以让我投入 0.02 美元。
weak_ptr
must somehow know when the corresponding shared_ptr
s have all gone out of scope and the pointed object has been deallocated and destroyed. This means that shared_ptr
s need to communicate the destruction towards each weak_ptr
to the same object somehow. This has a certain cost – for example, a global hash table needs to be updated, where weak_ptr
gets the address from (or nullptr
if the object is destroyed).
weak_ptr
必须以某种方式知道相应的shared_ptr
s何时全部超出范围并且指向的对象已被释放和销毁。这意味着shared_ptr
s 需要以weak_ptr
某种方式将每个对象的销毁传递给同一个对象。这有一定的成本——例如,需要更新全局哈希表,weak_ptr
从哪里获取地址(或者nullptr
对象是否被销毁)。
This also involves locking in a multi-threaded environment, so it can potentially be too slow for some tasks.
这还涉及在多线程环境中锁定,因此对于某些任务来说可能太慢了。
However, the goal of unique_ptr
is to provide a zero-costRAII-style abstraction class. Hence, it should not incur any other cost than that of delete
ing (or delete[]
ing) the dynamically allocated object. The delay imposed by doing a locked or otherwise guarded hash table access, for example, may be comparable to the cost of deallocation, however, which is not desirable in the case of unique_ptr
.
然而,目标unique_ptr
是提供一个零成本的RAII 风格的抽象类。因此,除了delete
ing(或delete[]
ing)动态分配的对象之外,它不应产生任何其他成本。例如,通过进行锁定或以其他方式受保护的哈希表访问所施加的延迟可能与解除分配的成本相当,然而,这在 的情况下是不可取的unique_ptr
。
回答by Bartosz Pi?kny
Looks like everyone is writing here about std::weak_ptr but not about weak poiner concept which I believe is what the author is asking for
看起来每个人都在这里写关于 std::weak_ptr 但不是关于弱指针概念,我相信这是作者所要求的
I think that no one mentioned why standard library is not providing weak_ptr for unique_ptr. Weak pointer CONCEPT doesn't disclaims unique_ptr usage. Weak pointer is only an information if the object has been already deleted so it's not a magic but very simple generalized observer pattern.
我认为没有人提到为什么标准库没有为 unique_ptr 提供 weak_ptr。弱指针概念并不否认 unique_ptr 的使用。如果对象已经被删除,弱指针只是一个信息,所以它不是魔术而是非常简单的通用观察者模式。
It's because of threadsafety and consistency with shared_ptr.
这是因为线程安全性和与 shared_ptr 的一致性。
You just simply can't guarantee that your weak_ptr (created from unique_ptr existing on other thread) will be not destroyed during calling method on pointed object. It's because weak_ptr needs to be consistent with std::shared_ptr which guarantee threadsafety. You can implement weak_ptr which works correctly with unique_ptr but only on the same thread - lock method will be unnecessary in this case. You can check chromium sources for base::WeakPtr and base::WeakPtrFactory - you can use it freely with unique_ptr. Chromium weak pointer code is most probably based on last member destruction - you need to add factory as a last member and after that I believe that WeakPtr is informed abut object deleteion (I'm not 100% sure) - so it doesn't looks so hard to implement.
你只是不能保证你的weak_ptr(从存在于其他线程上的unique_ptr创建)在调用指向对象的方法期间不会被破坏。这是因为weak_ptr 需要与保证线程安全的std::shared_ptr 保持一致。您可以实现weak_ptr,它可以与unique_ptr 一起正常工作,但只能在同一线程上运行——在这种情况下,不需要lock 方法。您可以检查 base::WeakPtr 和 base::WeakPtrFactory 的铬源 - 您可以通过 unique_ptr 自由使用它。Chromium 弱指针代码很可能基于最后一个成员销毁 - 您需要将工厂添加为最后一个成员,然后我相信 WeakPtr 会被通知邻接对象删除(我不是 100% 确定) - 所以它看起来并不太难实施了。
Overall using unique_ptr with weak pointer concept is OK IMHO.
总体而言,使用带有弱指针概念的 unique_ptr 是可以的,恕我直言。
回答by Christian Convey
It may be useful to distinguish reasons for preferring a unique_ptr
over a shared_ptr
.
区分偏爱 a 而unique_ptr
不是 a 的原因可能很有用shared_ptr
。
PerformanceOne obvious reason is computational-time and memory use. As currently defined, shared_ptr
objects typically need something like a reference-count value, which takes space and also must be actively maintained. unique_ptr
objects don't.
性能一个明显的原因是计算时间和内存使用。按照目前的定义,shared_ptr
对象通常需要引用计数值之类的东西,它占用空间并且还必须积极维护。 unique_ptr
对象没有。
SemanticsWith a unique_ptr
, you as the programmer have a pretty good idea when the pointed-to object is going to be destroyed: when the unique_ptr
is destroyed or when one of its modifying methods is called. And so on large or unfamiliar code bases, using unique_ptr
statically conveys (and enforces) some information about the program's runtime behavior that might not be obvious.
语义使用 a unique_ptr
,作为程序员的您可以很好地了解指向的对象何时将被销毁:何时unique_ptr
销毁或调用其修改方法之一。等等大型或不熟悉的代码库,使用unique_ptr
静态传达(并强制执行)一些关于程序运行时行为的信息,这些信息可能并不明显。
The comments above have generally focused on the performance-based reasons that it would be undesirable for weak_ptr
objects to be tied to unique_ptr
objects. But one might wonder if the semantics-based argument is sufficient reason for some future version of the STL to support the use-case implied by the original question.
上面的评论通常集中在基于性能的原因上,即不希望将weak_ptr
对象绑定到unique_ptr
对象。但是人们可能想知道基于语义的论点是否足以让某些未来版本的 STL 支持原始问题所暗示的用例。