std::shard_ptr是智能指针,通过引用计数的方式共享对象的所有权,在引用计数为0时自动释放对象占用的内存。
int main(){
int *p = new int(10);
std::shared_ptr<int> a(p, [](int* p) {std::cout << "[deleter called]\n"; delete p;});
std::cout << "p=" << p <<" a.get()=" << a.get() << " a=" << a << '\n';
std::shared_ptr<int> b(a);
std::cout << "b.use_count(): " << b.use_count() << '\n';
std::cout << "b=" << b <<" b.get()=" << b.get() << " a=" << a << '\n';
return 0;
}
运行信息:
p=0x798c20 a.get()=0x798c20 a=0x798c20
b.use_count(): 2
b=0x798c20 b.get()=0x798c20 a=0x798c20
通过打印信息,可以看出:p, a.get(), a, b, b.get()的值是一样的,是同一指针。
Note1:shared_ptr对象只能通过复制它们的值来共享所有权: 如果两个shared_ptr是从同一个(非shared_ptr)指针构造(或生成)的,它们都将拥有该指针,但不共享它,当其中一个释放该指针(删除其管理对象),而让另一个指向无效位置时,会导致潜在的访问问题。即上面的例子中,应该通过std::shared_ptr<int> b(a)定义对象b,这样引用计数会增加;而不应该通过std::shared_ptr<int> b(p)来定义对象b。
Note2: 循环引用导致的内存泄露问题。
#include <iostream>
#include <memory>
using namespace std;
class Abase;
class base {
public:
base(string name): mName(name) {
cout << "construct " << mName << endl;
}
virtual ~base() {
cout << "deconstruct " << mName << endl;
}
void print() {
cout << mName << " will print" << endl;
}
public:
string mName;
shared_ptr<Abase> base_ptr;
};
class Abase {
public:
Abase(string name):mName(name){
cout << "construct " << mName << endl;
}
virtual ~Abase() {
cout << "deconstruct " << mName << endl;
}
void print() {
cout << mName << " will print" << endl;
}
public:
string mName;
shared_ptr<base> Abase_ptr;
};
int main(int argc, char* argv[]) {
{
shared_ptr<Abase> A(new Abase("AAAAAAA"));
shared_ptr<base> B(new base("BBBBBBB"));
cout << B.use_count() << endl;
cout << A.use_count() << endl;
A->Abase_ptr = B;
B->base_ptr = A;
cout << B.use_count() << endl;
cout << A.use_count() << endl;
}
return 0;
}
日志输出:
construct AAAAAAA
construct BBBBBBB
1
1
2
2
weak_ptr可以与shared_ptr对象共享指针,而不需要拥有它们,即不会增加引用计数从而解决了shared_ptr循环引用导致的内存泄露问题。上面的例子只要将Abase或base中的指针类型改成weak_ptr即可走到各自的析构函数中。
shared_ptr中的reset()函数:释放shared_ptr对象共同拥有的对象的所有权,即共享所有权的引用计数减一。
weak_ptr中的lock和expired函数比较重要,因为它本身不会增加引用计数,所以它指向的对象可能在它用的时候已经被释放了,所以在用之前需要使用expired函数来检测是否过期,如果expired() == true(函数expired()的功能等价于use_count()==0),表示实际对象已经不复存在了,这个时候调用lock返回的是一个指向null的shared_ptr对象;如果expired() == false,可以使用lock函数来获取其对应的shared_ptr对象(lock()会创建shared_ptr指针,在该指针的作用域范围内,会使引用次数+1,出作用域,引用次数-1)。
参考:
shared_ptr和weak_ptr的区别与联系_haodada1226的博客-CSDN博客_shared_ptr weak_ptr