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