C++ 11 智能指针 自动内存管理

9 篇文章 0 订阅

自动内存管理

RAII(Resource Acquisition Is Initialization)资源获取即初始化

是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。

RAII 的一般做法是这样的:
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,
最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。

这种做法有两大好处:
①不需要显式地释放资源。
②采用这种方式,对象所需的资源在其生命期内始终保持有效。

此时,所托管的资源,随对象的创建而获取,随对象的消失而消失,
即所谓的 RAII思想:资源获取即初始化。
#include <iostream>
#include <memory>
using namespace  std;


class A{
public:
    A(){
        cout<<"A()"<<endl;
    }
    ~A(){
        cout<<"~A()"<<endl;
    }
    void dis(){
        cout<<"A::void dis()"<<endl;
    }
};
void func(){
    auto_ptr<A> ap(new A);
    ap->dis();

}

int main(){
    func();
}

原理上,是代理了被托管的对象指针,管理对象的生命周期,即实现自动释放。其
行为类似于所托管的对象指针,原因是,重载了 operator->和 operator*。

auto_ptr的弃用

#include <iostream>
#include <memory>
using namespace std;

int main()
{
    int *p = new int(10); // 动态分配一个 int,初始值为 10
    {
        unique_ptr<int> up(p); // 使用 unique_ptr 管理 p
        cout << *up << endl; // 输出 10
    } // up 超出作用域,自动释放 p

    // 这里再次使用 p 会导致未定义行为,因为 p 已经被释放
    unique_ptr<int> up2(p); // 这行代码会导致错误
    cout << *up2 << endl;

    // 正确的做法是直接使用 unique_ptr 管理动态内存
    unique_ptr<int> up3(new int(10));
    cout << *up3 << endl; // 输出 10

    return 0;
}

uniqu_ptr

uniqu_ptr 的使用方法,基本上等同于 auto_ptr, 不同之处,就在于实现了资源的
唯一, 既不可以拷贝也不可以赋值。

#include <iostream>
#include <memory>
using namespace  std;


class A{
public:
    A(){
        cout<<"A()"<<endl;
    }
    ~A(){
        cout<<"~A()"<<endl;
    }
    void dis(){
        cout<<"A::void dis()"<<endl;
    }
};
void func(){
    unique_ptr<A> ap(new A);//ok
    ap->dis();
    unique_ptr<A> ap2(ap);//编译不过
    ap2->dis();
}

int main(){
    func();
}

unique_ptr 可以用于数组。

#include <iostream>
#include <memory>
using namespace std;

class A {
public:
    // 构造函数
    A() {
        cout << "A()" << endl; // 输出构造函数被调用的信息
    }

    // 析构函数
    ~A() {
        cout << "~A()" << endl; // 输出析构函数被调用的信息
    }

    // 成员函数,用于显示信息
    void dis() {
        cout << "A::void dis()" << endl; // 输出成员函数被调用的信息
    }
};

int main() {
    // 创建一个 unique_ptr 智能指针,指向一个包含10个整数的数组,并初始化前四个元素
    unique_ptr<int[]> up(new int[10]{1, 2, 3, 4});

    // 遍历数组并输出每个元素的值
    for (int i = 0; i < 10; i++)
        cout << up[i] << endl;

    // 创建一个 unique_ptr 智能指针,指向一个包含20个A类对象的数组
    unique_ptr<A[]> up2(new A[20]);

    // 遍历数组并调用每个A类对象的dis()成员函数
    for (int i = 0; i < 20; i++)
        up2[i].dis();

    return 0; // 返回0,表示程序正常结束
}

unique_ptr 常用接口

在这里插入图片描述

#include <iostream>
#include <memory>
using namespace std;

class Copy {
public:
    // 构造函数,接受一个整数参数
    Copy(int i) : _i(new int(i)) {
        cout << "Copy(int i) " << "this: " << this << " _i " << _i << endl; // 输出构造函数被调用的信息
    }

    // 拷贝构造函数
    Copy(const Copy &another) : _i(new int(*another._i)) {
        cout << " Copy(const Copy & another)" << endl; // 输出拷贝构造函数被调用的信息
    }

    // 析构函数
    ~Copy() {
        cout << " ~Copy() " << this << endl; // 输出析构函数被调用的信息
    }

    // 成员函数,用于显示信息
    void dis() {
        cout << "Copy::void dis()" << endl; // 输出成员函数被调用的信息
    }

    int *_i; // 指向动态分配内存的指针
};

int main() {
    // 创建一个 unique_ptr 智能指针,托管一个新创建的 Copy 对象
    unique_ptr<Copy> up(new Copy(1));

    // 检查 unique_ptr 是否托管了资源
    if (!up) {
        cout << "无资源" << endl;
    } else {
        cout << "有资源" << endl;
    }

    // 获取托管资源的指针
    cout << up.get() << endl; // 输出托管资源的指针地址

    // 放弃托管,返回资源指针
    Copy *c = up.release();

    // 手动释放资源
    delete c;

    return 0; // 返回0,表示程序正常结束
}

reset

#include <iostream>
#include <memory>
using namespace std;

class Copy {
public:
    // 构造函数,接受一个整数参数
    Copy(int i) : _i(new int(i)) {
        cout << "Copy(int i) " << "this: " << this << " _i " << _i << endl; // 输出构造函数被调用的信息
    }

    // 拷贝构造函数
    Copy(const Copy &another) : _i(new int(*another._i)) {
        cout << " Copy(const Copy & another)" << endl; // 输出拷贝构造函数被调用的信息
    }

    // 析构函数
    ~Copy() {
        cout << " ~Copy() " << this << endl; // 输出析构函数被调用的信息
    }

    // 成员函数,用于显示信息
    void dis() {
        cout << "Copy::void dis()" << endl; // 输出成员函数被调用的信息
    }

    int *_i; // 指向动态分配内存的指针
};

int main() {
    {
        // 创建一个 unique_ptr 智能指针,托管一个新创建的 Copy 对象
        unique_ptr<Copy> up(new Copy(1));

        // 重置 unique_ptr,托管一个新的 Copy 对象,旧的资源会被释放
        up.reset(new Copy(2));

        // 重置 unique_ptr,不托管任何资源,旧的资源会被释放
        up.reset();

        cout << "{}内" << endl; 
    }
    cout << "{}外" << endl; 

    return 0; 
}

unique_ptr 移动

//todo unique_ptr 智能指针
#include <iostream>
#include <memory>
using namespace std;

class Copy
{
public:
    Copy(int i):_i(new int(i))
    {
        cout<<"Copy(int i) "<<"this: "<<this<<" _i "<<_i<<endl;
    }
    Copy(const Copy & another)
            :_i(new int(*another._i))
    {
        cout<<" Copy(const Copy & another)"<<endl;
    }
    ~Copy(){
        cout<<" ~Copy() "<<this<<endl;
    }

    // 成员函数,用于显示信息
    void dis() {
        cout << "Copy::void dis()  _i="<< *_i << endl; // 输出成员函数被调用的信息
    }
    int *_i;
};

int main(){

    unique_ptr<Copy> up(new Copy(100));

    unique_ptr<Copy> up2=std::move(up);

    up2->dis();//Copy::void dis()  _i=100
    up->dis();//up此时不再可用
    return 0;

}

shared_ptr

uinque_ptr 解决了 auto_ptr 中引用同一个对象的问题,方式就是不可引用同一个对象。

shared_ptr 解决了 auto_ptr 中引用同一个对象,共同拥有一个资源,
但不会重析构的问题,

原理是,在内部保持一个引用计数,并且仅当引用计数为 0 才能被删除,不可以用数组。

常用接口

在这里插入图片描述

引用计数

//todo shared_ptr 智能指针
#include <iostream>
#include <memory>
using namespace std;

void func(shared_ptr<int> sp)
{
//
    sp.reset(); //此处仅将自己所累积的计数减 1
    cout<<sp.use_count()<<endl;
    sp.reset(); //此时 reset 等价于 sp 对象消失,若己为零,则不再减 1.
}
int main(){
    //引用计数,每次被引用引用计数加1,对象消失-1
    shared_ptr<int> sp(new int(10));
    cout<<*sp<<endl;//10
    cout<<"use_count:"<<sp.use_count()<<endl;//use_count:1

    shared_ptr<int> sp2(sp);
    cout<<*sp2<<endl;//10

    cout<<"use_count:"<<sp.use_count()<<endl;//use_count:2
    cout<<"use_count:"<<sp2.use_count()<<endl;//use_count:2

    return 0;

}

shared_ptr单独的引用计数


#include <iostream>
#include <memory>
using namespace std;
class A
{
public:
    A()
    {
        cout<<"A()"<<this<<endl;
    }
    ~A()
    {
        cout<<"~A()"<<this<<endl;
    }
    void dis()
    {
        cout<<"A::void dis()"<<endl;
    }
};


int main()
{
    {
        //创建一个 shared_ptr 智能指针,托管一个新创建的 A 对象
        shared_ptr<A> sp(new A);
        //创建两个 shared_ptr 智能指针,共享同一个托管对象
        shared_ptr<A> sp2(sp);
        shared_ptr<A> sp3(sp);

        //输出当前托管对象的引用计数
        cout<<sp.use_count()<<endl;
        //重置 shared_ptr,减少引用计数,但不会影响其他 shared_ptr 的引用计数
        sp.reset();
        sp.reset();
        sp.reset();
        cout<<sp.use_count()<<endl;//0
        cout<<"+++++++++++++++++++++"<<endl;
    }
    cout<<"======================"<<endl;


}
输出
A()0x1544ddb1760
3
0
+++++++++++++++++++++
~A()0x1544ddb1760
======================

示例1


#include <iostream>
#include <memory>
using namespace std;
class A
{
public:
    A()
    {
        cout<<"A()"<<this<<endl;
    }
    ~A()
    {
        cout<<"~A()"<<this<<endl;
    }
    void dis()
    {
        cout<<"A::void dis()"<<endl;
    }
};

void func(shared_ptr<A> sp){
    sp.reset();
    //此时已经取消托管后面的sp.reset();无用
    sp.reset();
    cout<<sp.use_count()<<endl;//2
}
int main()
{
    shared_ptr<A> sp(new A);
    cout<<sp.use_count()<<endl;//1
    func(sp);
    cout<<sp.use_count()<<endl;//1
}

示例2


#include <iostream>
#include <memory>
using namespace std;
class A
{
public:
    A()
    {
        cout<<"A()"<<this<<endl;
    }
    ~A()
    {
        cout<<"~A()"<<this<<endl;
    }
    void dis()
    {
        cout<<"A::void dis()"<<endl;
    }
};

void func(shared_ptr<A> sp){
    if(sp.unique()){
        cout<<"true"<<endl;
    } else{
        cout<<"false"<<endl;//输出:false
    }


    sp.reset();
    //此时已经取消托管后面的sp.reset();无用
    sp.reset();
    cout<<sp.use_count()<<endl;//2
}
int main()
{
    shared_ptr<A> sp(new A);
    cout<<sp.use_count()<<endl;//1
    //判断sp托管是否唯一
    if(sp.unique()){
        cout<<"true"<<endl;//true
    }
    func(sp);
    cout<<sp.use_count()<<endl;//1
}

shared_ptr 移动

//todo shared_ptr 移动
#include <iostream>
#include <memory>
using namespace std;
class A
{
public:
    A()
    {
        cout<<"A()"<<this<<endl;
    }
    ~A()
    {
        cout<<"~A()"<<this<<endl;
    }
    void dis()
    {
        cout<<"A::void dis()"<<endl;
    }
};

int main()
{
    shared_ptr<A> sp(new A);
    shared_ptr<A> sp2(sp);
    shared_ptr<A> sp3(sp);
    cout<<sp.use_count()<<endl;//3

    shared_ptr<A> spm =std::move(sp);
    cout<<spm.use_count()<<endl;//3
    cout<<sp2.use_count()<<endl;//3
    cout<<sp3.use_count()<<endl;//3

}

shared_ptr 引用传递

//todo shared_ptr 移动
#include <iostream>
#include <memory>
using namespace std;
class A
{
public:
    A()
    {
        cout<<"A()"<<this<<endl;
    }
    ~A()
    {
        cout<<"~A()"<<this<<endl;
    }
    void dis()
    {
        cout<<"A::void dis()"<<endl;
    }
};


void func(shared_ptr<A>& sp){ //引用传递,,不用引用会use_count+1
    cout<<sp.use_count()<<endl;//1
}
int main()
{
    shared_ptr<A> sp(new A);
    func (sp);
    cout<<sp.use_count()<<endl;//1
    
}

  • 16
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MarkTop1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值