C++智能指针小结
C++ 11新增的智能指针有三个:unique_ptr, shared_ptr, weak_ptr
要包含的头文件 :memory.h
unique_ptr:只能有一个指针指向资源;
shared_ptr:多个指针可以指向同一个资源;
weak_ptr:用于弥补shared_ptr的不足,解决指针成环问题
定义一个指向类型为X的智能指针:
unique_ptr<X> pX(new X);
shared_ptr<X> pX(new X);
关于auto_ptr
auto_ptr是C++ 98中的智能指针,其功能类似于unique_ptr,但是auto_ptr存在隐式授权,相比于unique_ptr,auto_ptr不安全,unique_ptr只能使用显式授权(使用move函数)。
关于成环
智能指针成环代码如下:
#include "mainwindow.h"
#include <QApplication>
#include <memory>
#include <qdebug.h>
class TChild;
class TParent
{
public:
void SetChild(std::shared_ptr<TChild> const& Child)
{
Child_ = Child;
}
~TParent()
{
qDebug() << "Parent destructor called!";
}
private:
std::shared_ptr<TChild> Child_;
};
class TChild
{
public:
void SetParent(std::shared_ptr<TParent> const& Parent)
{
Parent_ = Parent;
}
~TChild()
{
qDebug() << "Child destructor called!";
}
private:
std::shared_ptr<TParent> Parent_;
};
int TestPtr()
{
std::shared_ptr<TParent> Parent = std::make_shared<TParent>();
std::shared_ptr<TChild> Child = std::make_shared<TChild>();
Parent->SetChild(Child);
Child->SetParent(Parent);
//超出作用域,局部变量析构,此时应该调用Parent和Child的析构函数,
//然而,结果并不如所愿,析构函数没有被调用
return 0;
}
int main(int argc, char *argv[])
{
TestPtr();
return 0;
}
执行结果:Parent和Child 实例在超出作用域时,析构函数没有被调用。
原因分析:注意这一行代码,Parent_ = Parent;智能指针的赋值运算会导致智能指针的引用计数 +1;程序中虽然只有一个Parent实例,实际Parent的引用计数为2(即两个指针指向数据),在超出作用域时,Parent智能指针引用计数-1,引用计数变为1,不会调用析构函数,此时Child智能指针引用计数依然是2,所以,Child也不会析构。
解决办法:引入weak_ptr(对weak_ptr的赋值操作不增加引用计数,从而解决智能指针成环问题)
weak_ptr不控制对象的生命期,但是它知道对象是否还活着。如果对象还活着,那么它可以提升为有效的shared_ptr(提升操作通过lock()函数获取所管理对象的强引用指针);如果对象已经死了,提升会失败,返回一个空的shared_ptr。
将上面的代码做如下修改,使用weak_ptr代替shared_ptr,将TParent类修改如下:
相关代码如下,做出更改的代码已经标出:
#include "mainwindow.h"
#include <QApplication>
#include <memory>
#include <qdebug.h>
class TChild;
class TParent
{
public:
void SetChild(std::shared_ptr<TChild> const& Child)
{
Child_ = Child;
}
~TParent()
{
qDebug() << "Parent destructor called!";
}
private:
std::shared_ptr<TChild> Child_;
};
class TChild
{
public:
void SetParent(std::shared_ptr<TParent> const& Parent)
{
Parent_ = Parent;
}
/*************************使用weak_ptr的方法***************************/
void UseParent()
{
//使用weak_ptr指向的对象之前通过lock()获得shared_ptr。
std::shared_ptr<TParent> Parent = Parent_.lock();
}
/*************************使用weak_ptr的方法***************************/
~TChild()
{
qDebug() << "Child destructor called!";
}
private:
/*************************在这里做出了更改***************************/
std::weak_ptr<TParent> Parent_;
/*************************在这里做出了更改***************************/
};
int TestPtr()
{
std::shared_ptr<TParent> Parent = std::make_shared<TParent>();
std::shared_ptr<TChild> Child = std::make_shared<TChild>();
Parent->SetChild(Child);
Child->SetParent(Parent);
//超出作用域,智能指针将调用析构函数
return 0;
}
int main(int argc, char *argv[])
{
TestPtr();
return 0;
}
shared_ptr 和 weak_ptr的作用原理请查看代码分析:https://blog.****.net/ithiker/article/details/51532484