C++ std::shared_ptr:reset() 与赋值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31438714/
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
std::shared_ptr: reset() vs. assignment
提问by AlwaysLearning
This is a basic question, but I did not find a previous post about it. The title of the following question sounds like it might be the same question as mine, but the question itself does not match the title: is it better to use shared_ptr.reset or operator =?
这是一个基本问题,但我没有找到以前的帖子。以下问题的标题听起来可能与我的问题相同,但问题本身与标题不匹配:使用 shared_ptr.reset 还是 operator = 更好?
I am confused about the purpose of the reset()
member function of std::shared_ptr
: what does it contribute in addition to the assignment operator?
我对reset()
成员函数的用途感到困惑std::shared_ptr
:除了赋值运算符之外,它还有什么作用?
To be concrete, given the definition:
具体来说,给出定义:
auto p = std::make_shared<int>(1);
Are the following two lines equivalent:
p = std::make_shared<int>(5); p.reset(new int(5));
What about these:
p = nullptr; p.reset();
以下两行是否等效:
p = std::make_shared<int>(5); p.reset(new int(5));
这些怎么样:
p = nullptr; p.reset();
If the two lines are equivalent in both cases, then what is the purpose of reset()
?
如果这两行在两种情况下都是等价的,那么 的目的是reset()
什么?
EDIT: Let me re-phrase the question to better emphasize its point. The question is: is there a case where reset()
lets us achieve something that is not as easily achievable without it?
编辑:让我重新表述这个问题以更好地强调它的观点。问题是:有没有一种情况reset()
可以让我们实现一些没有它就不容易实现的东西?
回答by NathanOliver
When using reset()
the parameter passed to reset need not be a managed object (nor can it be); whereas with =
the right hand side must be a managed object.
使用时reset()
传递给 reset 的参数不需要是托管对象(也不能是);而=
右手边必须是托管对象。
So these two lines give you the same end result:
所以这两行给你相同的最终结果:
p = std::make_shared<int>(5); // assign to a newly created shared pointer
p.reset(new int(5)); // take control of a newly created pointer
But we cannot do:
但我们不能这样做:
p = new int(5); // compiler error no suitable overload
p.reset(std::make_shared<int>(5).get()); // uh oh undefined behavior
Without reset()
you would not be able to reassign a shared pointer to a different raw pointer without creating a shared pointer and assigning it. Without =
you wouldn't be able to make a shared pointer point to another shared pointer.
如果reset()
没有创建共享指针并分配它,您将无法将共享指针重新分配给不同的原始指针。没有=
您将无法使共享指针指向另一个共享指针。
回答by Praetorian
It's possible for reset
to avoid a dynamic memory allocation in certain cases. Consider the code
这是可能的reset
,以避免在某些情况下,动态内存分配。考虑代码
std::shared_ptr<int> p{new int{}}; // 1
p.reset(new int{}); // 2
On line 1 there are 2 dynamic memory allocations happening, one for the int
object and a second one for the shared_ptr
's control block that'll keep track of the number of strong/weak references to the managed object.
在第 1 行,发生了 2 个动态内存分配,一个用于int
对象,第二个用于shared_ptr
的控制块,它将跟踪对托管对象的强/弱引用的数量。
On line 2 there is again a dynamic memory allocation for a new int
object. Within the body of reset
the shared_ptr
will determine that there are no other strong references to the previously managed int
, so it must delete
it. Since there aren't any weak references either, it could also deallocate the control block, but in this case it would be prudent for the implementation to reuse the same control block because it would otherwise have to allocate a new one anyway.
第 2 行再次为新int
对象进行动态内存分配。在身体reset
的shared_ptr
将确定有先前管理没有其它强引用int
,所以它必须delete
它。由于也没有任何弱引用,它也可以释放控制块,但在这种情况下,实现重用相同的控制块是谨慎的,因为否则无论如何它都必须分配一个新的。
The above behavior would not be possible if you always had to use assignment.
如果您总是不得不使用赋值,则上述行为是不可能的。
std::shared_ptr<int> p{new int{}}; // 1
p = std::shared_ptr<int>{new int{}}; // 2
In this case, the second call to the shared_ptr
constructor on line 2 has already allocated a control block, so p
will have to deallocate its own existing control block.
在这种情况下,第 2shared_ptr
行对构造函数的第二次调用已经分配了一个控制块,因此p
必须释放它自己现有的控制块。
回答by Alejandro
I won't include the rationale behind your first sub-question of the difference between construction via make_shared
or from a pointer, as this difference is highlighted in several different locations, including this excellent question.
我不会包括你的第一个子问题背后的基本原理,即通过make_shared
或从指针构造之间的差异,因为这种差异在几个不同的位置突出显示,包括这个很好的问题。
However, I think it is constructive to distinguish between using reset
and operator=
. The former relinquishes ownership of the resource managed by the shared_ptr
, either by destroying it if the shared_ptr
happened to be the sole owner, or by decrementing the reference count. The latter implies shared ownership with another shared_ptr
(unless you're move constructing).
但是,我认为区分使用reset
和是有建设性的operator=
。前者放弃由 管理的资源的所有权,shared_ptr
如果shared_ptr
碰巧是唯一所有者,则通过销毁它,或者通过减少引用计数。后者意味着与另一个人共享所有权shared_ptr
(除非您正在建造)。
As I mentioned in the comments, it's important that the pointer passed in to reset
not be owned by another shared or unique pointer, because it would yield undefined behavior upon the destruction of the two independent managers - they both would attempt to delete
the resource.
正如我在评论中提到的,重要的是传入的指针reset
不为另一个共享或唯一指针所有,因为它会在两个独立管理器销毁时产生未定义的行为 - 他们都会尝试delete
使用资源。
One use case of reset
could be lazy initialization of a shared resource. You only want the shared_ptr
to manage some resource, memory for example, if you really need it. Doing an outright allocation, such as:
一个用例reset
可能是共享资源的延迟初始化。shared_ptr
如果您真的需要它,您只想管理一些资源,例如内存。进行直接分配,例如:
std::shared_ptr<resource> shared_resource(new resource(/*construct a resource*/));
might be wasteful if its never actually needed. To do this with lazy initialization, something like this may apply:
如果从未真正需要它,则可能会浪费。要使用延迟初始化来做到这一点,可能适用于以下内容:
std::shared_ptr<resource> shared_resource;
void use_resource()
{
if(!shared_resource)
{
shared_resource.reset(new resource(...));
}
shared_resource->do_foo();
}
Using reset
in this case is more concise than doing a swap
or assigning to a temporary shared_ptr
.
reset
在这种情况下使用比执行 aswap
或分配给临时更简洁shared_ptr
。
回答by Guvante
reset()
changes the managed object of an existing shared_ptr
.
reset()
更改现有 的托管对象shared_ptr
。
p = std::shared_ptr(new int(5)); and p.reset(new int(5));
p = std::shared_ptr(new int(5)); 和 p.reset(new int(5));
The former involves creating a new shared_ptr
and moving it into a variable. The latter does not create a new object, it simply changes the underlying pointer in managed by the shared_ptr
.
前者涉及创建一个新的shared_ptr
并将其移动到一个变量中。后者不会创建新对象,它只是更改由shared_ptr
.
Put another way the two are meant to be used in different cases. Assignment is for when you have a shared_ptr
and reset
for when you have a raw pointer.
换句话说,这两者旨在用于不同的情况。分配是当你有一个shared_ptr
和reset
当你有一个原始指针。
Another thing to keep in mind is that shared_ptr
was available in boost before move assignment existed and influenced the latest version heavily. Without move assignment being able to change a shared_ptr
without making a copy is beneficial as it saves you the bookkeeping of the extra object.
要记住的另一件事是,shared_ptr
在移动分配存在并严重影响最新版本之前,它在 boost 中可用。无需移动分配,shared_ptr
无需复制即可更改 a是有益的,因为它可以为您节省额外对象的簿记。