C++智能指针,RAII(资源获取即初始化) 原则

转载:C++ RAII机制详解

转载:C++share_ptr智能指针的使用

中文标准库:RAII

一、unique_ptr

中文标准库:unique_ptr

尽量使用unique_ptr替代裸指针

一个unique_ptr独享它指向的对象,不能直接(使用reset才可以)将一个unique_ptr赋值给其他变量,不过shared_ptr可以。也就是说,同时只有一个unique_ptr指向同一个对象,当这个unique_ptr被销毁时,指向的对象也随即被销毁。如果一个类中包含unique_ptr,那么该类也不能使用拷贝和赋值。

数组版本

std::unique_ptr<int[]> ptr = std::make_unique<int[]>(5); //相当于 int ptr[5] = {0};

局部智能指针不能作为函数返回值,因为智能指针的作用域有限

指针

1. 获取裸指针 get()

返回指向被管理对象的指针

2. 替换被管理对象 reset()

注意:因为一个unique_ptr独享它指向的对象,因此替换被管理的对象时必须释放之前对象的所有权

std::unique_ptr<int> p1 = std::make_unique<int>(2);
std::unique_ptr<int> p2 = std::make_unique<int>(3);
p1 = p2;//错误
p1.reset(p2); //错误
p1.reset(p2.release()); //正确,此时p1管理的是大小为3的int数组对象

3. 释放被管理对象 release()

unique_ptr被销毁时(如离开作用域),对象也就自动释放了,也可以通过其他方式下显式释放对象。如:

up = nullptr; //置为空,释放up指向的对象
up.release(); //放弃控制权,返回裸指针,并将up置为空
up.reset();   //释放up指向的对象

release不会调用析构,只是释放控制权

4. std::unique_ptr和类的前置声明

//test.h
class A;
class B
{
  std::unique<A> m_a;
};

智能指针和类的前置声明

VS报错:can't delete an incomplete type 解决方法:将类的构造函数和析构函数在cpp文件中实现

二、share_ptr

尽量少用share_ptr

shared_ptr是支持共享所有权的引用计数型指针,“共享”指的是允许多个指针指向同一个资源,shared_ptr对象可以被拷贝与赋值,“引用计数”指的是它可以记录当前指向同一资源的指针的数量, 当计数为0的时候才会释放动态分配的对象。对shared_ptr循环引用会导致因为无法释放资源引发的内存泄漏。典型的如双链表。不要把一个裸指针给多个shared_ptr对象管理

#include <iostream>
#include <memory>

class B;

class A
{
public:
    A() = default;
    ~A() { std::cout << "~A\n"; }

    std::shared_ptr<B> _b;
};

class B
{
public:
    B() = default;
    ~B() { std::cout << "~B\n"; }

    std::shared_ptr<A> _a;
};


int main()
{
    auto pa = std::make_shared<A>();
    auto pb = std::make_shared<B>();

    pa->_b = pb;
    pb->_a = pa;

    std::cout << "A use count:" << pa.use_count() << std::endl; 
    std::cout << "B use count:" << pb.use_count() << std::endl;
}

输出如下

A use count:2
B use count:2

因为引用计数都是2,所以在main函数结束的时候,不会调用类A和类B的析构函数,就出现了内存泄漏。上面产生内存泄漏的原因,就是我们常说的循环引用

三、weak_ptr

weak_ptr就是为了辅助shared_ptr的,它本身不能直接指向原生指针对象,只能指向shared_ptr对象。

weak_ptr总结

  • weak_ptr虽然是一个模板类,但是不能用来直接定义指向原始指针的对象。

  • weak_ptr接受shared_ptr类型的变量赋值,但是反过来是行不通的,需要使用lock函数。

  • weak_ptr设计之初就是为了服务于shared_ptr的,所以不增加引用计数就是它的核心功能。

  • 由于不知道干了什么之后weak_ptr所指向的对象就会被析构掉,所以使用之前请先使用expired函数检测一下。

转载:智能指针(3):weak_ptr浅析

四、auto_ptr

被摒弃 https://www.cnblogs.com/lanxuezaipiao/p/4132096.html

示例代码

点击查看代码
#include <iostream>
#include <memory>

class A
{
public:
    std::shared_ptr<int> sharedInt = std::make_shared<int>(1);
    //std::unique_ptr<int> uniqueInt = std::make_unique<int>(2);
    void show() { std::cout << *sharedInt << "\n"; }
};

int main()
{
    A a;
    a.show();
    A a1 = a;  //如果类A中有unique_ptr报错
    A a2 = a1;

    std::cout << a.sharedInt.use_count();  //3

    ///< Shared_ptr
    auto s1 = std::make_shared<int>(1);
    auto s2 = std::make_shared<int>(2);
    auto s3 = std::make_shared<int>(3);

    std::shared_ptr<int> ps1;
    std::shared_ptr<int> ps2;
    auto c1 = s1.use_count(); //1
    auto c2 = s2.use_count(); //1
    auto c3 = s3.use_count(); //1
    auto c4 = ps1.use_count(); //0
    auto c5 = ps2.use_count(); //0

    ps1 = s1;  //共享s1指向的对象(unique_ptr不支持)
    auto c6 = ps1.use_count(); //2
    auto c7 = s1.use_count(); //2
    ps2 = s1;
    auto c8 = s1.use_count(); //3
    auto c9 = ps2.use_count(); //3


    ///< unique_ptr
    std::unique_ptr<int> pu1 = std::make_unique<int>(2);
    std::unique_ptr<int> pu2 = std::make_unique<int>(3);
    //p1.reset(p2); //错误
    //std::unique_ptr<int> pu6 = pu1; //错误,因为unique_ptr独享它指向的对象(可以用shared_ptr共享)
    pu1.reset(pu2.release()); //正确,此时p1管理的是值为3的int指针

    auto pu1Value1 = *pu1.get();

    std::unique_ptr<int[]> pu3 = std::make_unique<int[]>(9);  //大小为9的int数组
    std::unique_ptr<int[]> pu4 = std::unique_ptr<int[]>(new int[3]); //大小为3的int数组,不推荐使用new

    std::unique_ptr<int[]> pu5;

    int arr[5] = { 0 };
    int* pu6 = new int[8];
    pu4.reset(arr);
    pu5.reset(pu6);

    //std::unique_ptr<int[]> pu7(pu3);  //错误
    std::unique_ptr<int[]> pu7(std::move(pu3));//正确

    //pu5.reset(std::move(pu3));  //错误
    //pu4.reset(pu3); //错误
    pu5.reset(pu3.release()); //正确

    (*pu1) = 99;  //给pu1赋值
    auto pu1Value2 = *pu1;


    system("pause");
    return 0;
}

原文链接: https://www.cnblogs.com/mmmmmmmmm/p/14512823.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    C++智能指针,RAII(资源获取即初始化) 原则

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/404193

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月24日 下午6:44
下一篇 2023年4月24日 下午6:44

相关推荐