C++在使用new创建一个对象后,如果不使用delete释放的话,可能会造成内存的泄露。因此C++设计了智能指针,可以自动的释放内存。常见的有:
shared_ptr:允许多个指针指向同一个对象。
unique_ptr:指针独占一个对象。
weak_ptr:弱指针。
使用智能指针的时候,要包含头文件#include< memory>
shared_ptr
shared_ptr存在一个计数功能。每当一个指针指向同一个对象时,计数就会加1。每删除一个指针,计数就会减1。当计数为0时,就会释放内存(对于new\delete一般在构造函数中new,在析构函数中delete)。
#include <iostream>
#include <memory>
using namespace std;
void calcul_num(shared_ptr<int> i)
{
(*i)++;
}
int main()
{
shared_ptr<int> a = make_shared<int>(10);
calcul_num(a);
cout<<*a<<endl; // 输出为11
}
可以使用get获得原始指针,使用use_count查找一个对象的使用次数。
#include <iostream>
#include <memory>
using namespace std;
int main()
{
int temp = 10;
shared_ptr<int> a1 = make_shared<int>(temp);
shared_ptr<int> a2 = a1;
shared_ptr<int> a3 = a1;
int* p = a2.get();
// a1,a2,a3共用一片内存,修改a1的值,a2也会跟着变化
*a1 = 100;
cout<<*a2<<endl;
// 输出为3 3 3
cout<<a1.use_count()<<" "<<a2.use_count()<<" "<<a3.use_count()<<endl;
a1.reset(); //释放a1
// 输出为0 2 2
cout<<a1.use_count()<<" "<<a2.use_count()<<" "<<a3.use_count()<<endl;
a2.reset(); //释放a2
// 输出为0 0 1
cout<<a1.use_count()<<" "<<a2.use_count()<<" "<<a3.use_count()<<endl;
// 智能指针+new开辟内存
shared_ptr<string> sp(new string("hellow"));
shared_ptr<string> sp2 = sp;
cout<<sp.use_count()<<endl;
cout<<*sp<<endl;
}
#include <iostream>
#include <memory>
using namespace std;
struct ListNode
{
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
ListNode(){}
};
int main(int argc,char* argv[])
{
ListNode* ln = new ListNode(100);
shared_ptr<ListNode*> node = make_shared<ListNode*>(ln);
(*node)->val = 10;
cout<<(*node)->val<<endl;
cout<<node.use_count()<<endl;
}
unique_ptr
unique_ptr指针禁止和其他指针共用一个对象。因此当unique_ptr销毁时,其指向的对象也会被销毁。
unique_ptr只能使用new来进行初始化,不支持普通拷贝和赋值。
#include <iostream>
#include <memory>
using namespace std;
int main()
{
// unique_ptr只能使用new来进行赋值
unique_ptr<int> a1(new int(10));
// 错误,unique_ptr不支持拷贝
// unique_ptr<int> a2(a1);
// 错误,unique_ptr不允许多个指针指向同一个对象
// unique_ptr<int> a2 = a1;
}
可以使用move实现unique_ptr的转移
#include <iostream>
#include <memory>
using namespace std;
int main()
{
// unique_ptr只能使用new来进行赋值
unique_ptr<int> a1(new int(10));
// 将a1移动给a2,此时a1被释放。
unique_ptr<int> a2 = move(a1);
// unique_ptr<int> a2(move(a1));
// 错误,此时a1已经被释放了
// cout<<*a1<<endl;
// 输出为10
cout<<*a2<<endl;
}
weak_ptr
弱指针,绑定到一个shared_ptr对象,不会改变shared_ptr的引用计数。当最后一个shared_ptr指针被销毁后,其所指向的对象就会被释放。此时即使有weak_ptr指针指向该对象,依旧会被释放。
#include <iostream>
#include <memory>
using namespace std;
int main()
{
weak_ptr<int> wp;
{
shared_ptr<int> w = make_shared<int>(10);
wp = w;
// 输出为1,可见weak_ptr并没有改变shared_ptr的指向对象的引用次数。
cout<<wp.use_count()<<endl;
}
// 输出为0
cout<<wp.use_count()<<endl;
}
验证:
#include <iostream>
#include <memory>
#include <string>
using namespace std;
void test_weak_ptr(weak_ptr<string>& wp)
{
if(shared_ptr<string> sp = wp.lock())
cout<<"weak_ptr不为空"<<endl;
else
cout<<"weak_ptr为空"<<endl;
if(!wp.expired())
{
shared_ptr<string> sp = wp.lock();
cout<<"对象为"<<*sp<<endl;
}
}
int main()
{
shared_ptr<string> sp = make_shared<string>("hellow world");
// 创建一个弱引用指向sp。
weak_ptr<string> wp1(sp);
weak_ptr<string> wp2(sp);
// 此时wp1不为空。
test_weak_ptr(wp1);
// 此时sp指向的对象释放掉,wp1变为空。
sp.reset();
test_weak_ptr(wp1);
}
//weak_ptr不为空
//对象为hellow world
//weak_ptr为空
需要注意的是,弱指针reset()之后,并不会释放对象的内存。
#include <iostream>
#include <memory>
#include <string>
using namespace std;
void test_weak_ptr(weak_ptr<string>& wp)
{
if(shared_ptr<string> sp = wp.lock())
cout<<"weak_ptr不为空"<<endl;
else
cout<<"weak_ptr为空"<<endl;
if(!wp.expired())
{
shared_ptr<string> sp = wp.lock();
cout<<"对象为"<<*sp<<endl;
}
}
int main()
{
shared_ptr<string> sp = make_shared<string>("hellow world");
// 创建一个弱引用指向sp。
weak_ptr<string> wp1(sp);
weak_ptr<string> wp2(sp);
wp1.reset();
test_weak_ptr(wp2);
}
//weak_ptr不为空
//对象为hellow world
weak_ptr解决的问题
当创建智能指针spA,spB时,计数+1。当shared_ptr类型的spA、spB对象析构时,ref_count 减一;由于Obj A 和 Obj B中的shared_ptr智能指针还相互引用,导致ref_count不为零,spA和spB不会去析构所指的对象,最终导致内存泄漏。
#include <iostream>
#include <memory>
#include <string>
using namespace std;
class A;
class B;
class A
{
public:
shared_ptr<B> ObjA;
};
class B
{
public:
shared_ptr<A> ObjB;
};
int main()
{
weak_ptr<A> temp_A;
weak_ptr<B> temp_B;
shared_ptr<A> spA = make_shared<A>();
shared_ptr<B> spB = make_shared<B>();
spA->ObjA = spB;
spB->ObjB = spA;
temp_A = spA;
temp_B = spB;
spA.reset();
spB.reset();
cout<<"spA次数:"<<temp_A.use_count()<<endl;
cout<<"spB次数:"<<temp_B.use_count()<<endl;
}
// 输出为
// spA次数:1
// spB次数:1
// 可见内存没有被释放,存在内存泄露
将类中的shared_ptr改为weak_ptr,此时类间的相互引用为弱指针,不算入计数次数中。
#include <iostream>
#include <memory>
#include <string>
using namespace std;
class A;
class B;
class A
{
public:
weak_ptr<B> ObjA;
};
class B
{
public:
weak_ptr<A> ObjB;
};
int main()
{
weak_ptr<A> temp_A;
weak_ptr<B> temp_B;
shared_ptr<A> spA = make_shared<A>();
shared_ptr<B> spB = make_shared<B>();
spA->ObjA = spB;
spB->ObjB = spA;
temp_A = spA;
temp_B = spB;
spA.reset();
spB.reset();
cout<<"spA次数:"<<temp_A.use_count()<<endl;
cout<<"spB次数:"<<temp_B.use_count()<<endl;
}
// 输出为
// spA次数:0
// spB次数:0
// 可见内存被释放