使用普通指针,容易造成堆内存泄露(忘记释放),二次释放,程序发生异常
时内存泄露等问题等,使用智能指针能更好的管理堆内存。
unique_ptr,shared_ptr, weak_ptr是三种C++11支持的常用的智能指针,接下来分别观察它们的性质和一些简单应用,体会一下:
shared_ptr的实现:指向堆上创建的对象的裸指针(raw_ptr)和指向内部隐藏的、共享的管理对象(share_count_object)。
PS:共享堆上对象的所有权,性能略差
①对shared_ptr的初始化优先使用make_share。
auto sp1 = make_shared(100);//一次就能完成定义指针、长度分配
//相当于
shared_ptr sp1(new int(100));//先完成指针定义,再分配长度
②智能指针是一个包含指针和计数的结构体,不能直接像裸指针一样赋值
std::shared_ptr p = new int(1);//错误
那么通过这几个典型案例总结一下我们需要掌握的常用函数(注意注释),也是这几个指针的共性:
#include
#include
using namespace std;
int main()
{
auto sp1 = make_shared(100); // 优先使用make_shared来构造智能指针
shared_ptr sp2(new int(100));
std::shared_ptr p1;
p1.reset(new int(1)); //reset有参数就是初始化,没参数就是释放(变0)
std::shared_ptr p2 = p1;
// ******引用计数此时应该是2,多次引用++操作
cout << "p2.use_count() = " << p2.use_count()<< endl;
p1.reset(); //主动释放
cout << "p1.reset()\n";
// 引用计数此时应该是1(即有多少个指针引用)
cout << "p2.use_count()= " << p2.use_count() << endl;
if(!p1) { //p1为空就是0
cout << "p1 is empty\n";
}
if(!p2) {
cout << "p2 is empty\n";
}
p2.reset();
cout << "p2.reset()\n";
cout << "p2.use_count()= " << p2.use_count() << endl;
if(!p2) {
cout << "p2 is empty\n";
}
return 0;
}
管理非new对象或是没有析构函数的类时,应当为其传递合适的删除器。
#include
#include
using namespace std;
void DeleteIntPtr(int *p) {
cout << "call DeleteIntPtr" << endl;
delete p;
}
int main()
{
std::shared_ptr p(new int(1), DeleteIntPtr);//这里的删除器是一个函数
std::shared_ptr p2(new int(1), [](int *p) {
cout << "call lambda delete p" << endl;
delete p;});//这里的删除器是一个lamda函数
std::shared_ptr p3(new int[10], [](int *p) { delete []p;}); //若删除的是new type[](也就是动态数组),删除时加[]
return 0;
}//这里要注意析构的顺序,以免造成一次删多个的崩溃(先外再内)
#include
#include
using namespace std;
class A: public std::enable_shared_from_this //这里不声明将会造成重复析构,因为同位置智能指
//针数量增加,但share_count_object不增加
{
public:
shared_ptrGetSelf()
{
return shared_from_this();
}
~A()
{
cout << "Deconstruction A" << endl;
}
};
int main()
{
// shared_ptr sp1(new A);
// shared_ptr sp2 = sp1->GetSelf(); // ok
shared_ptr sp2;
{
shared_ptr sp1(new A);
sp2 = sp1->GetSelf(); // 通过share_from_this这个函数帮助打到count增加的目的
}
cout << "leave {}" << endl;
return 0;
}
unique_ptr是一个独占型的智能指针,它不允许其他的智能指针共享其内部的指针。通过代码理解一下。(用的比较少)
Ps:独占对象的所有权,没有引用计数,性能较好
#include
#include
using namespace std;
void test1()
{
unique_ptr my_ptr(new int); // 正确
if(!my_ptr) {
cout << "1 my_ptr is null" << endl ;
unique_ptr my_other_ptr = std::move(my_ptr); // 正确,(unique的赋值)
//(把my_ptr资源移走)
if(!my_ptr) {
cout << "2 my_ptr is null" << endl ;
}
}
void test2()
{
// unique_ptr可以指向一个数组
std::unique_ptr ptr(new int[10]);
ptr[9] = 9;
// std::shared_ptr ptr2(new int[10]); // 这个是不合法的
// unique_ptr指定删除器和shared_ptr有区别
std::shared_ptr ptr3(new int(1), [](int *p){delete p;}); // 正确
// std::unique_ptr ptr4(new int(1), [](int *p){delete p;}); // 错误
std::unique_ptr ptr5(new int(1), [](int *p){delete p;}); // 正确
std::unique_ptr ptr6(new int(1), [](int *p){delete p;}); // 正确
cout << "main finish!" << endl;
}
int main()
{
test1();
// test2();
cout << "main finish!" << endl;
return 0;
}
share_ptr虽然已经很好用了,但是有一点share_ptr智能指针还是有内存泄露的情况,当两个对象相互使用一个shared_ptr成员变量指向对方,会造成循环引用,使引用计数失效,从而导致内存泄漏。
①weak_ptr 是一种不控制对象生命周期(不影响count)的智能指针, 它指向一个 shared_ptr 管理的对象. 进行该对象的内存管理的是那个强引用的shared_ptr, weak_ptr只是提供了对管理对象的一个访问手段。
②weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。
③weak_ptr是用来解决shared_ptr相互引用时的死锁问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放。weak_ptr是对对象的一种弱引用,不会增加对象的引用计数,和shared_ptr之间可以相互转化,shared_ptr可以直接赋值给它,它可以通过调用lock函数来获得shared_ptr。
#include
#include
using namespace std;
class A;
class B;
class A {
public:
std::shared_ptr bptr;
~A() {
cout << "A is deleted" << endl; //析构函数后,才会释放成员变量
}
};
class B {
public:
std::shared_ptr aptr;
~B() {
cout << "B is deleted" << endl;
}
};
int main()
{
{
std::shared_ptr ap(new A);
std::shared_ptr bp(new B);
ap->bptr = bp;
bp->aptr = ap;
// 是否可以手动释放呢?-----是可以的
//ap.reset()or bp.reset();
}
cout<< "main leave" << endl; // 循环引用导致ap bp退出了作用域都没有析构
return 0;
}
#include
#include
using namespace std;
void test1()
{
cout << "---- test1 ------------------" << endl;
weak_ptr wp;
{
shared_ptr sp(new int(1)); //sp.use_count()==1
wp = sp; //wp不会改变引用计数,所以sp.use_count()==1
shared_ptr sp_ok = wp.lock(); //wp没有重载->操作符。只能这样取所指向的对象
}
shared_ptr sp_null = wp.lock(); //sp_null .use_count()==0;
if(wp.expired()) {//weap 不能直接操作成员变量
cout << "shared_ptr is destroy" << endl;
} else {
cout << "shared_ptr no destroy" << endl;
}
}
void test2()
{
cout << "---- test2 ------------------" << endl;
weak_ptr wp;
shared_ptr sp_ok;
{
shared_ptr sp(new int(1)); //sp.use_count()==1
wp = sp; //wp不会改变引用计数,所以sp.use_count()==1
sp_ok = wp.lock(); ****//不能直接赋值,需要借助lock获取
}
if(wp.expired()) {
cout << "shared_ptr is destroy" << endl;
} else {
cout << "shared_ptr no destroy" << endl;
}
}
int main()
{
test1();
test2();
return 0;
}