具体而言,考虑到定义:
auto p = std::make_shared<int>(1);
以下两行代码是否等价:
p = std::make_shared<int>(5); p.reset(new int(5));
这些怎么样:
如果在两种情况下这两行是等效的,那么p = nullptr; p.reset();
reset()
的目的是什么?
编辑:让我重新表述问题以更好地强调其重点。问题是:是否存在一种情况,reset()
可以让我们实现一些不太容易实现的东西?
auto p = std::make_shared<int>(1);
以下两行代码是否等价:
p = std::make_shared<int>(5);
p.reset(new int(5));
这些怎么样:
p = nullptr;
p.reset();
如果在两种情况下这两行是等效的,那么reset()
的目的是什么?
reset()
可以让我们实现一些不太容易实现的东西?使用 reset()
时,传递给 reset() 的参数不需要是托管对象(也不能是),而使用 =
时,右侧必须是托管对象。
因此,这两行代码将给您相同的结果:
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
但是我们无法做到:
p = new int(5); // compiler error no suitable overload
p.reset(std::make_shared<int>(5).get()); // uh oh undefined behavior
如果没有reset()
,你将无法重新分配共享指针到另一个原始指针而不创建一个共享指针并将其分配。如果没有=
,你将无法使一个共享指针指向另一个共享指针。
reset()
可以让我实现一些不容易实现的东西? - AlwaysLearningmake_shared
创建的 shared_ptr 与通过 .reset(new T)
创建的 shared_ptr 是不同的。 - Yakk - Adam Nevraumontmake_shared
可以将指针和共享状态分配到单个对象中,只需调用一次new。当您执行reset时,必须将其拆分为两个单独的分配。 - NathanOliverreset
在某些情况下可以避免动态内存分配。考虑以下代码:
std::shared_ptr<int> p{new int{}}; // 1
p.reset(new int{}); // 2
int
对象,另一个是为shared_ptr
的控制块进行分配,控制块将跟踪对托管对象的强/弱引用数。int
对象进行动态内存分配。在reset
函数体内,shared_ptr
将确定以前托管的int
没有其他强引用,因此必须delete
它。由于也没有任何弱引用,它也可以释放控制块,但在这种情况下,实现最好重用相同的控制块,因为否则它仍然需要分配一个新的控制块。std::shared_ptr<int> p{new int{}}; // 1
p = std::shared_ptr<int>{new int{}}; // 2
shared_ptr
构造函数已经分配了一个控制块,因此p
将必须释放自己现有的控制块。sizeof(ControlBlock) + sizeof(T)
做出决策,认为避免动态分配更值得。然后它可以销毁对象,但不释放控制块并获取新指针的所有权。 - Praetorianreset
会鼓励不良实践,应该避免使用,但我认为这是一个正确的答案。在某些情况下,使用 reset
可能是一种性能优化,但在进行更改之前,我会检查改进是否可衡量。 - Chris Drewmake_shared
胜过reset
,具体取决于实际使用的shared_ptr
。换句话说,仅查看修改shared_ptr的性能是不足够的,而是要考虑修改+使用的综合性能影响。(这排除了没有任何真实使用场景的小型通用测试)。 - AnorZaken我不会解释你第一个子问题的理由,即通过make_shared
或指针构建之间的区别,因为这个区别在几个不同的地方都有强调,包括这个优秀的问题。
然而,我认为区分使用reset
和operator=
是有益的。前者通过销毁它来放弃由shared_ptr
管理的资源(如果shared_ptr
恰好是唯一的所有者),或者通过递减引用计数。后者意味着与另一个shared_ptr
共享所有权(除非你正在移动构造)。
正如我在评论中提到的,重要的是将传递给reset
的指针不被另一个shared或unique指针所拥有,因为在两个独立的管理器被销毁时,这将导致未定义的行为——它们都将尝试删除资源。
reset
的一个用例可能是共享资源的惰性初始化。只有在真正需要时,你才希望shared_ptr
管理某些资源,例如内存。进行直接分配,例如:
std::shared_ptr<resource> shared_resource(new resource(/*construct a resource*/));
std::shared_ptr<resource> shared_resource;
void use_resource()
{
if(!shared_resource)
{
shared_resource.reset(new resource(...));
}
shared_resource->do_foo();
}
reset
比执行 swap
或分配给临时的 shared_ptr
更加简洁。shared_ptr
共享所有权。我认为你的意思是将其与reset()
进行对比,后者使p
成为非托管资源的所有者,这意味着独占所有权。我越读越想知道:谁会使用reset()
?有没有使用此工具的示例? - AlwaysLearningshared_resource = std::make_shared<resource>(...);
非常简洁。 - Chris Drewreset()
函数用于改变现有shared_ptr
的托管对象。
p = std::shared_ptr(new int(5)); 和 p.reset(new int(5));
前者涉及创建新的shared_ptr
并将其移动到变量中。后者不会创建新的对象,它只是简单地改变由shared_ptr
托管的底层指针。
换句话说,这两个函数适用于不同的情况。赋值用于当您拥有一个shared_ptr
时,而reset
用于当您拥有一个原始指针时。
另一件需要记住的事情是,在移动分配之前,shared_ptr
已经在boost中可用,并且对最新版本产生了很大影响。没有移动分配能够改变shared_ptr
而不制作副本是有益的,因为它节省了额外对象的簿记工作。
shared_ptr
自 C++11 标准才存在:http://en.cppreference.com/w/cpp/memory/shared_ptr。 Boost 库有一个 C++03 的 shared_ptr
。 - NathanOliver
shared_ptr
和使用make_shared
之间的区别,这应该很容易找到。提示:有一个区别,有时它可能是显著的。 - Ulrich Eckhardtshared_ptr
上调用reset
并传递该内存块,会发生什么。当这两个指针超出范围时,它们将尝试删除相同的内存块 - 因此会导致未定义的行为。 - Alejandrop = std::shared_ptr<int>(new int(5));
е’Ңp.reset(new int(5));
гҖӮзҺ°еңЁжңүд»Җд№ҲеҢәеҲ«пјҹ - AlwaysLearningauto p = std::make_shared<int>(1); p = nullptr;
我认为它无法编译。 - John