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.csdn.net/ithiker/article/details/51532484