更多教程笔记请查看我的上一篇文章:点击跳转

C++11(RAll智能指针)自学之旅开始!

本次将介绍C++11最有用的更新:智能指针

长久以来C++的内存管理机制就一直被人诟病,没有GC回收,需要手动释放分配的内存,很容易被忘记释放内存的程序员造成内存泄漏,甚至被linux之父Linus炮轰C++是一门很烂的语言

详情请点击这里

但是C++也在不断的改进自身,不断的吸取教训,我相信C++未来会越来越好!

说回话题本身,智能指针是一个可以帮助C++程序员自动释放所分配内存的强大利器,不过用得好和用不好是两回事,下面我们来看一下智能指针的诞生原因:

概念代码:

//智能指针
#include <iostream>
#include "stdfix.h"
using namespace std;
// c语言当中对文件的操作
FILE *open_file(char *name)
{
    FILE *fp = NULL;
    fp = fopen(name, "rb++");
    return fp;
}
class CTest
{
public:
    CTest()
    {
        cout << "构造函数" << endl;
        //申请堆区资源
        m_pInt = new int;
    }
    ~CTest()
    {
        cout << "析构函数" << endl;
        if (m_pInt != nullptr)
        {
            //释放资源
            delete m_pInt;
            m_pInt = nullptr;
        }
    }

private:
    int *m_pInt;
};
//创建一个全局对象,全局对象有构造有析构,在对象创建和销毁前编译器都会主动调用构造和析构函数
//利用这个机制即可解决手动释放资源所带来的问题
CTest test;

int main()
{
    // c++需要自己管理堆内存的申请和释放
    int *p = new int;
    delete p;

    //有的时候会忘记资源的释放导致资源泄漏

    return 0;
}

看明白了吧,在对象创建和销毁前编译器都会主动调用构造和析构函数,这便是智能指针诞生的原因

智能指针便是简化了上述操作,在对象创建后由智能指针来接管,就算不手动释放内存,智能指针也会自动调用析构帮你释放,不得不说C++真是太强大了!

话不多说,我们一起来看看智能指针的实际操作:

实战代码:

//智能指针-unique_ptr独占指针
#include <iostream>
#include <string>
//想用智能指针必须包含这个头文件
#include <memory>
using namespace std;
class Cat
{
public:
    //默认构造
    Cat() = default;
    //有参构造函数
    Cat(string name)
    {
        this->m_Name = name;
    }
    //析构函数
    ~Cat()
    {
        cout << "Destructor of Cat: " << m_Name << endl;
    }

    //成员函数 默认不可修改
    void cat_info() const
    {
        cout << "cat info name: " << m_Name << endl;
    }
    string get_name() const
    {
        return m_Name;
    }
    //将内部的m_Name修改
    void set_cat_name(const string &name)
    {

        this->m_Name = name;
    }

private:
    //创建一个变量给予默认值
    string m_Name{"Mimi"};
};
int main()
{
    //调用有参构造和成员函数
    Cat c1("ok");
    c1.cat_info();
    //下面是局部作用域,在结束前会自动调用析构
    {
        Cat c1("ok");
        c1.cat_info();
    }

    //在堆区开辟内存并调用有参构造
    Cat *c_p1 = new Cat("yy");
    c_p1->cat_info();
    {
        Cat *c_p1 = new Cat("yy_scope");
        c_p1->cat_info();
        //手动释放
        delete c_p1;
    }
    //手动释放
    delete c_p1;

    //手动释放非常的不安全,所以需要智能指针
    //智能指针会自动的释放内存,不需要手动释放
    // unique_ptr的第一种用法:
    //向堆区申请内存
    Cat *c_p2 = new Cat("yz");

    //创建一个智能指针指向那个指向堆区内存的指针
    unique_ptr<Cat> u_c_p2{c_p2};

    c_p2->cat_info();
    u_c_p2->cat_info();
    //当指针内部的变量修改后
    c_p2->set_cat_name("ok");
    //智能指针也会修改
    u_c_p2->cat_info();
    delete c_p2;
    c_p2 = nullptr;
    //当堆区的内存释放后就无法再通过智能指针调用了
    // u_c_p2->cat_info();

    //第二种用法:
    //在堆区创建时就用智能指针指向那个指向堆区内存的指针
    unique_ptr<Cat> u_c_p3{new Cat("dd")};
    u_c_p3->cat_info();
    u_c_p3->set_cat_name("oo");
    u_c_p3->cat_info();

    //第三种用法 利用make_unique默认创建,调用默认构造函数
    unique_ptr<Cat> u_c_p4 = make_unique<Cat>();
    u_c_p4->cat_info();
    u_c_p4->set_cat_name("oo");
    u_c_p4->cat_info();

    // get和常量类型
    unique_ptr<int> u_i_1{new int(100)};
    //通过get就可以打印int的地址
    cout << "int address: " << u_i_1.get() << endl;
    cout << "cat address: " << u_c_p3.get() << endl;
    //解引用
    cout << *u_i_1 << endl;
    unique_ptr<int> u_i_p2 = make_unique<int>(200);
    cout << *u_i_p2 << endl;
    cout << u_i_p2.get() << endl;

    return 0;
}