shared_ptr 的 reset() 有 4 个重载版本,如下:
void reset() noexcept; (1) (since C++11)
template< class Y >
void reset( Y* ptr ); (2) (since C++11)
template< class Y, class Deleter >
void reset( Y* ptr, Deleter d ); (3) (since C++11)
template< class Y, class Deleter, class Alloc >
void reset( Y* ptr, Deleter d, Alloc alloc ); (4) (since C++11)
常用到的应该是前 3 个版本,这里不举例第 4 个版本,因为我也没用过^_^
1,void reset() 版本
这个函数是最简单的,其作用:释放托管对象的所有权(如果有),调用后,该智能指针不再管理任何对象。注意,这里的释放并不是真正地去释放,只是引用计数减 1,而释放是引用计数为 0 时自行进行的。
#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;
};
void deleter(Foo *f)
{
delete []f;
}
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().
return 0;
}

可以看到在调用 reset() 后,调用了对象的析构函数进行释放。我们看 reset() 的另一种情况:
#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 << "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';
std::shared_ptr<Foo> sptr1 = sptr;
// Reset the shared_ptr without handing it a fresh instance of Foo.
// The old instance will be destroyed after this call.
std::cout << "call sptr1.reset()...\n";
sptr1.reset(); // not 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().
return 0;
}
可以看到 Foo::bar = 100, use_count() = 2,此时两个智能指针都管理着 0x1029028 的资源,当调用 sptr1.reset(); 后,这个资源就少了一个管理者,所以 After reset(): use_count() = 1, sptr = 0x1029028,当离开作用域后,此资源才被释放。
2,模板版本带一个参数
template< class Y >
void reset( Y* ptr ); 用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 << "\n1) 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.
return 0;
}

可以看到在 sptr.reset(new Foo{222}); 后,释放了 0x17d1028 指向的资源,当前指向的资源为 0x17d1040,离开作用域后自动释放。
3, 模板版本还两个参数
template<class Y, class Deleter>
void reset(Y *ptr, Deleter d)
带删除器的版本只会用在数组对象释放的情况,如果是数组对象的情况下不用删除器,则行为是未定义的。如:
#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(new Foo[3]); // 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().
return 0;
}

正确用法可以是这样:
#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;
};
void customDeleter(Foo *f)
{
if(f)
{
delete []f;
}
}
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(new Foo[3], customDeleter); // 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().
return 0;
}
添加删除函数:
void customDeleter(Foo *f)
{
if(f)
{
delete []f;
}
}
reset 调用时指定删除器: sptr.reset(new Foo[3], customDeleter);
因为只有释放数组对象时才需要指定删除器,所以实现就是 delete [],我们看结果:

最后调用的 3 个析构函数。
还可以使用 std::default_delete 模板,如:sptr.reset(new Foo[3], std::default_delete<Foo[]>());
#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(new Foo[3], std::default_delete<Foo[]>());
std::cout << "After reset(): use_count() = " << sptr.use_count()
<< ", sptr = " << sptr << '\n';
} // No call to Foo's destructor, it was done earlier in reset().
return 0;
}

同样释放正常。