C++智能指针

一,什么是智能指针
在C++中没有垃圾回收机制,必须自己释放分配的内存,否则就会造成内存泄露。解决这个问题最有效的方法是使用智能指针(smart pointer)。智能指针是存储指向动态分配(堆)对象指针的类,用于生存期的控制,能够确保在离开指针所在作用域时,自动地销毁动态分配的对象,防止内存泄露。智能指针的核心实现技术是引用计数,每使用它一次,内部引用计数加1,每析构一次内部的引用计数减1,减为0时,删除所指向的堆内存。

 c++中用的最多的是下面三种智能指针
C++11中提供了三种智能指针,使用这些智能指针时需要引用头文件<memory>

std::shared_ptr:共享的智能指针
std::unique_ptr:独占的智能指针
std::weak_ptr:弱引用的智能指针,它不共享指针,不能操作资源,是用来监视shared_ptr的。
 下面对他们分别进行分析
二,共享的智能指针shared_ptr
首先了解一下基本概念,再看代码,会学的很快
1. shared_ptr的初始化
 共享智能指针是指多个智能指针可以同时管理同一块有效的内存,共享智能指针shared_ptr 是一个模板类,如果要进行初始化有三种方式:通过构造函数、std::make_shared辅助函数以及reset方法。共享智能指针对象初始化完毕之后就指向了要管理的那块堆内存,如果想要查看当前有多少个智能指针同时管理着这块内存可以使用共享智能指针提供的一个成员函数use_count

2.获取原始指针

 对应基础数据类型来说,通过操作智能指针和操作智能指针管理的内存效果是一样的,可以直接完成数据的读写。但是如果共享智能指针管理的是一个对象,那么就需要取出原始内存的地址再操作,可以调用共享智能指针类提供的get()方法得到原始地址

3. 指定删除器
 当智能指针管理的内存对应的引用计数变为0的时候,这块内存就会被智能指针析构掉了。另外,我们在初始化智能指针的时候也可以自己指定删除动作,这个删除操作对应的函数被称之为删除器,这个删除器函数本质是一个回调函数,我们只需要进行实现,其调用是由智能指针完成的。

 上面三个基本知识点了解以后就可以轻松的阅读代码了(代码注释都非常的详细哦!)

#include <iostream>
using namespace std;
#include <string>
#include <memory>
 
class Test
{
public:
    Test() : m_num(0)
    {
        cout << "construct Test..." << endl;
    }
 
    Test(int x) : m_num(0)
    {
        cout << "construct Test, x = " << x << endl;
    }
 
    Test(string str) : m_num(0)
    {
        cout << "construct Test, str = " << str << endl;
    }
 
    ~Test()
    {
        cout << "destruct Test..." << endl;
    }
 
    void setValue(int v)
    {
        this->m_num = v;
    }
 
    void print()
    {
        cout << "m_num: " << this->m_num << endl;
    }
 
private:
    int m_num;
};
 
int main()
{
    /*--------------------------  一,初始化智能指针shared_ptr  ------------------------------*/
    //1.通过构造函数初始化
    shared_ptr<int> ptr1(new int(3));
    cout << "ptr1管理的内存引用计数: " << ptr1.use_count() << endl;
 
    //2.通过移动和拷贝构造函数初始化
    shared_ptr<int> ptr2 = move(ptr1);
    cout << "ptr1管理的内存引用计数: " << ptr1.use_count() << endl;
    cout << "ptr2管理的内存引用计数: " << ptr2.use_count() << endl;
 
    shared_ptr<int> ptr3 = ptr2;
    cout << "ptr2管理的内存引用计数: " << ptr2.use_count() << endl;
    cout << "ptr3管理的内存引用计数: " << ptr3.use_count() << endl;
 
    //3.通过 std::make_shared初始化
    shared_ptr<int> ptr4 = make_shared<int>(8);
    shared_ptr<Test> ptr5 = make_shared<Test>(7);
    shared_ptr<Test> ptr6 = make_shared<Test>("GOOD LUCKLY!");
 
    //4.通过reset初始化
    ptr6.reset(); //重置ptr6, ptr6的引用基数为0
    cout << "ptr6管理的内存引用计数: " << ptr6.use_count() << endl;
 
    ptr5.reset(new Test("hello")); //重置了指针的指向对象,原来的对象已经释放
    cout << "ptr5管理的内存引用计数: " << ptr5.use_count() << endl;
 
    cout << endl;
    cout << endl;
 
    /*--------------------------  二,共享智能指针shared_ptr的使用  ------------------------------*/
    //1.方法一
    Test* t = ptr5.get();
    t->setValue(1000);
    t->print();
 
    //2.方法二
    ptr5->setValue(7777);
    ptr5->print();
 
    printf("\n\n");
    /*------------------------------------  三,指定删除器  -----------------------------------*/
     //1.简单举例
    shared_ptr<Test> ppp(new Test(100), [](Test* t) {
        //释放内存
        cout << "Test对象的内存被释放了......." << endl;
        delete t;
        });
    printf("----------------------------------------------------------------------\n");
 
    2.如果是数组类型的地址,就需要自己写指定删除器,否则内存无法全部释放
    //shared_ptr<Test> p1(new Test[5], [](Test* t) {
    //    delete[]t;
    //    });
 
    //3.也可以使用c++给我们提供的 默认删除器函数(函数模板)
    shared_ptr<Test> p2(new Test[3], default_delete<Test[]>());
 
    //4.c++11以后可以这样写 也可以自动释放内存
    shared_ptr<Test[]> p3(new Test[3]);
 
    return 0;
}


 另外,我们还可以自己封装一个函数模板make_shared_array方法来让shared_ptr支持数组,代码如下:

#include <iostream>
#include <memory>
#include <string>
using namespace std;
 
//有了这个函数模板,我们就不用自己去释放数组类型的地址了
template <typename T>
shared_ptr<T> make_share_array(size_t size) 
{
    //返回匿名对象
    return shared_ptr<T>(new T[size], default_delete<T[]>());
}
 
int main()
{
    shared_ptr<int> ptr1 = make_share_array<int>(10);
    cout << ptr1.use_count() << endl;
 
    shared_ptr<string> ptr2 = make_share_array<string>(7);
    cout << ptr2.use_count() << endl;
        
    return 0;
}

三,独占的智能指针unique_ptr
首先了解一下基本概念,再看代码,会学的很快
 1. 初始化
std::unique_ptr是一个独占型的智能指针,它不允许其他的智能指针共享其内部的指针,可以通过它的构造函数初始化一个独占智能指针对象,但是不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr。

 2. 删除器
 unique_ptr指定删除器和shared_ptr指定删除器是有区别的,unique_ptr指定删除器的时候需要确定删除器的类型,所以不能像shared_ptr那样直接指定删除器

#include <iostream>
using namespace std;
#include <string>
#include <memory>
#include <functional>
 
class Test
{
public:
    Test() : m_num(0)
    {
        cout << "construct Test..." << endl;
    }
 
    Test(int x) : m_num(1)
    {
        cout << "construct Test, x = " << x << endl;
    }
 
    Test(string str) : m_num(2)
    {
        cout << "construct Test, str = " << str << endl;
    }
 
    ~Test()
    {
        cout << "destruct Test..." << endl;
    }
 
    void setValue(int v)
    {
        this->m_num = v;
    }
 
    void print()
    {
        cout << "m_num: " << this->m_num << endl;
    }
 
private:
    int m_num;
};
 
int main()
{
    /*--------------------------  一,初始化智能指针unique_ptr  ------------------------------*/
    //1.通过构造函数初始化
    unique_ptr<int> ptr1(new int(3));
 
    //2.通过移动函数初始化
    unique_ptr<int> ptr2 = move(ptr1);
 
    //.通过reset初始化
    ptr2.reset(new int(7));
 
    /*--------------------------  二,unique_ptr的使用  ------------------------------*/
    //1.方法一
    unique_ptr<Test> ptr3(new Test(666));
    Test* pt = ptr3.get();
    pt->setValue(6);
    pt->print();
 
    //2.方法二
    ptr3->setValue(777);
    ptr3->print();
 
    /*------------------------------------  三,指定删除器  -----------------------------------*/
    //1.函数指针类型
    //using ptrFunc = void(*)(Test*);
    //unique_ptr<Test, ptrFunc> ptr4(new Test("hello"), [](Test* t) {
    //    cout << "-----------------------" << endl;
    //    delete t;
    //    });
 
    //2.仿函数类型(利用可调用对象包装器)
    unique_ptr<Test, function<void(Test*)>> ptr4(new Test("hello"), [](Test* t) {
        cout << "-----------------------" << endl;
        delete t;
        });
 
    /*---------- 四,独占(共享)的智能指针可以管理数组类型的地址,能够自动释放 ---------*/
    unique_ptr<Test[]> ptr5(new Test[3]);
 
    //在c++11中shared_ptr不支持下面的写法,c++11以后才支持的
    shared_ptr<Test[]> ptr6(new Test[3]);
 
    return 0;
}

c++11 条款21:尽量使用std::make_unique和std::make_shared而不直接使用new_coolmeme的博客-CSDN博客_make_unique

四, 弱引用的智能指针weak_ptr
 弱引用智能指针std::weak_ptr可以看做是shared_ptr的助手,它不管理shared_ptr内部的指针。std::weak_ptr没有重载操作符*和->,因为它不共享指针,不能操作资源,所以它的构造不会增加引用计数,析构也不会减少引用计数,它的主要作用就是作为一个旁观者监视shared_ptr中管理的资源是否存在。

 1 初始化

#include <iostream>
#include <memory>
using namespace std;
 
int main() 
{
    shared_ptr<int> sp(new int);
 
    weak_ptr<int> wp1;
    weak_ptr<int> wp2(wp1);
    weak_ptr<int> wp3(sp);
    weak_ptr<int> wp4;
    wp4 = sp;
    weak_ptr<int> wp5;
    wp5 = wp3;
    
    return 0;
}


weak_ptr<int> wp1;构造了一个空weak_ptr对象
weak_ptr<int> wp2(wp1);通过一个空weak_ptr对象构造了另一个空weak_ptr对象
weak_ptr<int> wp3(sp);通过一个shared_ptr对象构造了一个可用的weak_ptr实例对象
wp4 = sp;通过一个shared_ptr对象构造了一个可用的weak_ptr实例对象(这是一个隐式类型转换)
wp5 = wp3;通过一个weak_ptr对象构造了一个可用的weak_ptr实例对象
 通过调用std::weak_ptr类提供的use_count()方法可以获得当前所观测资源的引用计数
 2.常用函数
 通过调用std::weak_ptr类提供的expired()方法来判断观测的资源是否已经被释放
通过调用std::weak_ptr类提供的lock()方法来获取管理所监测资源的shared_ptr对象
通过调用std::weak_ptr类提供的reset()方法来清空对象,使其不监测任何资源

浅谈shared_ptr及shared_ptr涉及到的循环引用问题_小葱1024的博客-CSDN博客_shared_ptr循环引用

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++智能指针是一种用于管理动态分配的内存资源的工具。C++中提供了多种类型的智能指针,其中包括shared_ptr、unique_ptr和weak_ptr。这些智能指针都位于头文件<memory>中。 其中,shared_ptr是一种引用计数智能指针,它允许多个智能指针共享同一个对象。shared_ptr通过对对象的引用计数来管理内存的释放,当引用计数为0时,即没有智能指针指向该对象时,对象会被自动释放。使用shared_ptr需要包含头文件<memory>,并通过new关键字创建动态分配的对象并将其交给shared_ptr进行管理。 另一种智能指针是unique_ptr,它是一种独占型智能指针,只能有一个智能指针拥有对对象的所有权。当unique_ptr对象被销毁时,它所管理的对象也会被自动释放。unique_ptr提供了更高效的内存管理方式,因为它不需要进行引用计数。使用unique_ptr也需要包含头文件<memory>,并使用new关键字创建动态分配的对象并将其交给unique_ptr进行管理。 除了shared_ptr和unique_ptr,还有其他类型的智能指针,如weak_ptr和scoped_ptr。weak_ptr是一种弱引用智能指针,它用于解决shared_ptr可能出现的循环引用问题。scoped_ptr是一种简单的智能指针,它只能在创建时初始化,并且不能进行复制和赋值操作。scoped_ptr在其所属的作用域结束时自动释放所管理的对象。 总结起来,C++智能指针是一种用于管理动态分配的内存资源的工具,包括shared_ptr、unique_ptr、weak_ptr和scoped_ptr等类型。它们提供了一种更安全、更高效的内存管理方式,避免了手动释放内存的麻烦。要使用这些智能指针,需要包含头文件<memory>,并通过new关键字创建动态分配的对象并将其交给相应的智能指针进行管理。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [C++ -- 智能指针C++11与boost库的智能指针及其使用)](https://blog.csdn.net/xu1105775448/article/details/80625936)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [C++智能指针的底层实现原理](https://blog.csdn.net/ArtAndLife/article/details/120793343)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值