std::shared_ptr<T>::reset
声明
// 1)
void reset() noexcept;
// 2)
template< class Y >
void reset( Y* ptr );
// 3)
template< class Y, class Deleter >
void reset( Y* ptr, Deleter d );
// 4)
template< class Y, class Deleter, class Alloc >
void reset( Y* ptr, Deleter d, Alloc alloc );
将管理的对象替换为 ptr
指向的对象。可以选择提供一个可选的删除器 d
,当没有 shared_ptr
对象拥有新对象时,它将被用于销毁该对象。默认情况下,使用 delete 表达式作为删除器。对于提供的类型,总是会选择正确的 delete 表达式,这就是为什么该函数被实现为使用单独参数 Y
的模板。
如果 *this
已经拥有一个对象,并且它是最后一个拥有该对象的 shared_ptr
,则该对象将通过其拥有的删除器进行销毁。
如果 ptr
指向的对象已经被拥有,该函数通常会导致未定义行为。
释放管理对象的所有权(如果有)。调用后,*this
不再管理任何对象。等效于 shared_ptr().swap(*this)
;
2-4)
将管理的对象替换为 ptr
指向的对象。Y 必须是完整类型,并且可以隐式转换为 T
。此外
- 2) 使用 delete 表达式作为删除器。必须提供有效的 delete 表达式,即 delete
ptr
必须是格式良好、具有明确定义的行为且不抛出任何异常。等效于shared_ptr<T>(ptr).swap(*this);
。 -
- 使用指定的删除器 d 作为删除器。删除器 d 必须可用于类型 T,即 d(ptr) 必须是格式良好、具有明确定义的行为且不抛出任何异常。删除器必须是
CopyConstructible
,并且其复制构造函数和析构函数不得抛出异常。等效于shared_ptr<T>(ptr, d).swap(*this);
。
- 使用指定的删除器 d 作为删除器。删除器 d 必须可用于类型 T,即 d(ptr) 必须是格式良好、具有明确定义的行为且不抛出任何异常。删除器必须是
-
- 与 (3) 相同,但额外使用
alloc
的副本用于内部使用的数据分配。Alloc
必须是一个Allocator
。复制构造函数和析构函数不得抛出异常。等效于shared_ptr<T>(ptr, d, alloc).swap(*this);
。
- 与 (3) 相同,但额外使用
参数
ptr
- 指向要获取所有权的对象 d
- 用于销毁对象的存储的删除器 alloc
- 用于内部分配的分配器
返回值
(无)
异常
std::bad_alloc
如果所需的额外内存无法获得。可能因其他错误而抛出实现定义的异常。如果发生异常,则调用 delete ptr
。
3-4)
std::bad_alloc
如果所需的额外内存无法获得。可能因其他错误而抛出实现定义的异常。如果发生异常,则调用 d(ptr)
。
示例
#include <memory>
#include <iostream>
struct Foo {
Foo(int n = 0) noexcept : bar(n) {
std::cout << "Foo::Foo(), bar = " << bar << " @ " << this << '\n';
}
~Foo() {
std::cout << "Foo::~Foo(), bar = " << bar << " @ " << this << "\n";
}
int getBar() const noexcept { return bar; }
private:
int bar;
};
int main()
{
std::cout << "1) unique ownership\n";
{
std::shared_ptr<Foo> sptr = std::make_shared<Foo>(100);
std::cout << "Foo::bar = " << sptr->getBar() << ", use_count() = "
<< sptr.use_count() << '\n';
// Reset the shared_ptr without handing it a fresh instance of Foo.
// The old instance will be destroyed after this call.
std::cout << "call sptr.reset()...\n";
sptr.reset(); // calls Foo's destructor here
std::cout << "After reset(): use_count() = " << sptr.use_count()
<< ", sptr = " << sptr << '\n';
} // No call to Foo's destructor, it was done earlier in reset().
std::cout << "\n2) unique ownership\n";
{
std::shared_ptr<Foo> sptr = std::make_shared<Foo>(200);
std::cout << "Foo::bar = " << sptr->getBar() << ", use_count() = "
<< sptr.use_count() << '\n';
// Reset the shared_ptr, hand it a fresh instance of Foo.
// The old instance will be destroyed after this call.
std::cout << "call sptr.reset()...\n";
sptr.reset(new Foo{222});
std::cout << "After reset(): use_count() = " << sptr.use_count()
<< ", sptr = " << sptr << "\nLeaving the scope...\n";
} // Calls Foo's destructor.
std::cout << "\n3) multiple ownership\n";
{
std::shared_ptr<Foo> sptr1 = std::make_shared<Foo>(300);
std::shared_ptr<Foo> sptr2 = sptr1;
std::shared_ptr<Foo> sptr3 = sptr2;
std::cout << "Foo::bar = " << sptr1->getBar() << ", use_count() = "
<< sptr1.use_count() << '\n';
// Reset the shared_ptr sptr1, hand it a fresh instance of Foo.
// The old instance will stay shared between sptr2 and sptr3.
std::cout << "call sptr1.reset()...\n";
sptr1.reset(new Foo{333});
std::cout << "After reset():\n"
<< "sptr1.use_count() = " << sptr1.use_count()
<< ", sptr1 @ " << sptr1 << '\n'
<< "sptr2.use_count() = " << sptr2.use_count()
<< ", sptr2 @ " << sptr2 << '\n'
<< "sptr3.use_count() = " << sptr3.use_count()
<< ", sptr3 @ " << sptr3 << '\n'
<< "Leaving the scope...\n";
} // Calls two destructors of: 1) Foo owned by sptr1,
// 2) Foo shared between sptr2/sptr3.
}
1) unique ownership
Foo::Foo(), bar = 100 @ 0x23c5040
Foo::bar = 100, use_count() = 1
call sptr.reset()...
Foo::~Foo(), bar = 100 @ 0x23c5040
After reset(): use_count() = 0, sptr = 0
2) unique ownership
Foo::Foo(), bar = 200 @ 0x23c5040
Foo::bar = 200, use_count() = 1
call sptr.reset()...
Foo::Foo(), bar = 222 @ 0x23c5050
Foo::~Foo(), bar = 200 @ 0x23c5040
After reset(): use_count() = 1, sptr = 0x23c5050
Leaving the scope...
Foo::~Foo(), bar = 222 @ 0x23c5050
3) multiple ownership
Foo::Foo(), bar = 300 @ 0x23c5080
Foo::bar = 300, use_count() = 3
call sptr1.reset()...
Foo::Foo(), bar = 333 @ 0x23c5050
After reset():
sptr1.use_count() = 1, sptr1 @ 0x23c5050
sptr2.use_count() = 2, sptr2 @ 0x23c5080
sptr3.use_count() = 2, sptr3 @ 0x23c5080
Leaving the scope...
Foo::~Foo(), bar = 300 @ 0x23c5080
Foo::~Foo(), bar = 333 @ 0x23c5050