⭐上篇文章:43.C++11-lambda表达式的使用-CSDN博客

⭐本篇代码:c++-learning-of-yzc: c++/数据结构/算法的学习记录 (gitee.com)

目录

一. 智能指针简介

二. 共享智能指针 shared_ptr

2.1 初始化

2.2 shared_ptr相关操作

2.3 shared_ptr使用注意与循环引用问题

三. 弱引用智能指针weak_ptr

四. auto_ptr 和 unique_ptr

4.1 auto_ptr

4.2 unique_ptr


一. 智能指针简介

        智能指针是用于解决传统指针的内存泄漏问题,智能可以可以自动释放开辟的资源。还能用于解决共享所有权指针的释放问题(比如多个指针指向同一个对象进行释放问题)

注:

        智能指针本身是线程安全的,但是管理的对象不一定是线程安全的

        智能指针的原理是RAII,构造时候开辟,析构时候释放。下篇文章会详细说明

C++中使用智能指针需要包含头文件memroy并且只有c++11以上版本支持

二. 共享智能指针 shared_ptr

        shared_ptr是共享智能指针,即可以多个指针管理同一个对象。

2.1 初始化

        shared_ptr可以通过构造函数,拷贝构造,make_shared函数三种方式初始化。代码如下

#include <iostream>
#include <memory>
#include <string>

int main()
{
    // 构造函数初始化
    std::shared_ptr<std::string> ps1(new std::string("Hello World!"));

    // 拷贝构造,这里使用匿名对象进行拷贝。
    std::shared_ptr<std::string> ps2 = std::shared_ptr<std::string>(new std::string("Hello World!"));

    // make_shared 这个使用比较方便,推荐使用
    // make_shared可以不用传入指针,直接传值即可自动构造智能指针
    auto ps3 = std::make_shared<std::string>("Hello World!");

    std::cout << "ps1:" << *ps1 << std::endl;
    std::cout << "ps2:" << *ps2 << std::endl;
    std::cout << "ps3:" << *ps3 << std::endl;
    
    return 0;
}

一般都推荐使用 make_shared。效率和安全性比较高

2.2 shared_ptr相关操作

get函数,可以通过get这个函数获取shared_ptr管理对象的裸指针。但是不建议使用这个操作

reset:用于重置shared_ptr

假如有一个shared_ptr P:

        如果P使用的reset且不带参数的P.reset(),此时shared_ptr的引用计数会减一,并且将P置空。如果引用计数-1之后为0,此时会销毁这个对象

        如果P是带参数的(P.reset(otherP)),如果P是这个对象的唯一智能指针,此时会释放这个对象,并且指向新的对象。反之,P对象的智能指针的引用计数-1,然后指向新对象

2.3 shared_ptr使用注意与循环引用问题

1 不要在函数参数中构建智能指针

2 不能同时将一个裸指针托管给两个智能指针,这样会导致析构异常(shared_ptr的共享的实现需要通过 拷贝和赋值来实现)

在类的内部,不要使用this指针作为共享指针的右值返回,与第二条一样,这样会导致this指针被两个即以上的智能指针管理并且每一个控制块不一样!需要使用shared_from_this()来解决这个问题

        另外,还需要注意智能指针的循环引用问题!假如有这样两个类

class A
{
public:
    shared_ptr<B> a;
};

class B
{
public:
    shared_ptr<A> a;
};

A中哦有B的智能指针,B中有A的智能指针。他们相互包含

        此时如果我们创建了一个A对象,一个B对象。如果我们分别创建两个智能指针sp1,sp2分别管理两个对象那么他们的结构如下

此时A对象shared_ptr和B对象的shared_ptr的引用计数都是2

当程序结束时候,sp1和sp2就会销毁,各自引用计数-1,引用计数变为1。

引用计数不为0,两个对象都不会销毁

此时结构如下

然后b指针想要销毁,必须要先销毁A对象,即销毁a指针

而销毁a指针的时候又要先销毁B对象,即销毁b指针。

结果就是我销毁的前提是我被销毁了。这样导致死循环。这种问题就是循环引用问题

        解决循环引用问题可以使用weak_ptr(弱引用智能指针)

三. 弱引用智能指针weak_ptr

        weak_ptr它只是用于解决shared_ptr的循环引用问题。

        原理是:weak_ptr只观察对象,不会增加引用计数。在上面例子中,如果使用weak_ptr。

class A
{
public:
    weak_ptr<B> a;
};

class B
{
public:
    weak_ptr<A> a;
};

当两个对象创建的时候,引用计数为1(weak_ptr不会增加引用计数)

但销毁的时候,引用计数-1。

此时引用计数为0,两个对象都销毁了。

        因此weak_ptr可以打破shared_ptr的循环引用。

四. auto_ptr 和 unique_ptr

4.1 auto_ptr

        auto_ptr是早版本的智能指针,它通过转移管理权来实现功能。但是这样会导致原先的指针在转移之后会被置空。

        那么原先的指针就无法使用了,并且会有空指针解引用问题出现,所以这个智能指针引进被废弃了。

4.2 unique_ptr

        unique_ptr是独占指针,无法被拷贝。可以理解为无法拷贝的shared_ptr。由于无法被拷贝,就不会出现多个指针指向同一个对象的而导致多次销毁问题。

        unique_ptr的使用方式与shared_ptr非常类似

代码如下:

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐