【C++】智能指针

        手动管理内存,使用new、delete与C++中最常见的BUG——内存泄漏息息相关。尽管都知道使用new申请一块内存都应手动使用delete释放这块内存,但是随着代码复杂度的提升,一个指针或许会在多个函数中频繁传递,很多时候会使程序员犯错误,忘记释放内存,或者不知道应该在哪里释放内存。

        C++中也提供了一种方法——智能指针,它可以自动地释放对象所占用的内存,并避免常见的内存泄漏和悬挂指针等问题。

        不过,智能指针也有其限制和潜在的开销,因此在使用时需要根据具体情况进行权衡和选择。

        C++标准库里面提供了两种主要的智能指针类型:std::shared_ptr 和 std::unique_ptr。       

std::shared_ptr一种共享拥有权的智能指针
std::unique_ptr一种独占所有权的智能指针

        当使用智能指针时需要引用<memory>标准库头文件。

#include <memory>

铺垫 

        先看下面代码:

void func(){
    int a = 100;    //栈内存,他的内存是由编译器自动分配的
    int* p = &a;    //p存储了a的地址
}

        如注释所言,函数中 a 的内存是由编译器自动分配的,在函数结束时,编译器会自动释放 a 的内存。

        与之相对的,我们也可以用new这个关键字自己动态请求一些内存。

void func(){
    int *p = new int;
}

         上述代码就动态请求一个int大小的内存。用new请求的内存,我们要用delete手动释放,不然,它是不会自动释放的,如下:

void func(){
    int *p = new int;
    delete p;
}

        这里的delete是释放了p指向的内存,不是删除了p本身,在删除之后还可以把p指向别的地方。如下:

void func(){
    int a = 100;
    int *p = new int;
    delete p;
    p = &a;
}

        new不仅可以用来请求单个内存,还可以用来请求用多个元素组成的数组,只需要加上 [] 和元素的个数就可以了。如下:

void func(){
    int *p = new int[100];
    delete[] p;
}

        如果用new的时候请求了多个元素,那么在delete的时候也应该加上 [] ,不过delete的方括号不需要元素的个数,因为编译器会帮你记下来,你创建了多少个元素。 

        当调用一个函数,其中局部变量就分配在栈内存上面,函数调用结束局部变量就会自动释放,这个过程由编译器自动控制。堆内存用于动态分配内存,动态分配的意思就是,需要程序员手动去请求这块内存,使用完之后需要程序员手动释放,不然这块内存就会一直存在,造成内存泄漏。

        如果在函数里面动态请求了一块内存,函数结束之后也没有手动释放掉,那么这块内存就会一直存在,但是别人也无法访问这块内存,因为唯一知道这块内存位置的指针p已经随着函数执行完毕被释放掉了,就会造成资源的浪费。久而久之,内存资源就会被完全的榨干,就没有内存可以使用了,造成系统的崩溃。

注意:

        对于一个指针不要删两次。undefined behavior。

int *p = new int;
delete p;
delete p;    //错误

共享智能指针

        顾名思义,共享智能指针std::shared_ptr 是一种共享拥有权的智能指针,允许多个指针共同拥有同一个对象。它跟踪有多少个 shared_ptr 实例指向同一个对象,并在最后一个 shared_ptr被销毁时释放该对象。

std::shared_ptr的使用方式如下:

  1. 创建std::shared_ptr对象并初始化:

    std::shared_ptr<Type> ptr = std::make_shared<Type>(args);
    

    这将创建一个指向类型为Type的对象的shared_ptr,并使用args参数初始化对象。

  2. 使用std::shared_ptr指针:

    • 通过->操作符访问对象的成员:
      ptr->memberFunction();
      ptr->memberVariable = value;
      
    • 通过*操作符解引用指针并访问对象的成员:
      (*ptr).memberFunction();
      (*ptr).memberVariable = value;
      
  3. 共享拥有权:

    • std::shared_ptr赋值给其他std::shared_ptr对象,实现共享拥有权:
      std::shared_ptr<Type> ptr2 = ptr;
      
    • 在函数间传递std::shared_ptr作为参数,共享拥有权:
      void someFunction(std::shared_ptr<Type> ptr);
      
  4. 手动释放对象:

    • 如果不再需要共享对象,可以将std::shared_ptr重置为nullptr,以释放对象:
      ptr.reset();
      

请注意,当最后一个std::shared_ptr指向对象时,对象将被自动释放。使用std::shared_ptr时,避免循环引用,以免导致内存泄漏。

独占智能指针

std::unique_ptr是一种独占拥有权的智能指针,它提供了以下使用方式:

  1. 创建std::unique_ptr对象并初始化:
    std::unique_ptr<Type> ptr = std::make_unique<Type>(args);
    

    这将创建一个指向类型为Type的对象的unique_ptr,并使用args参数初始化对象。

  2. 使用std::unique_ptr指针:

    • 通过->操作符访问对象的成员:
      ptr->memberFunction();
      ptr->memberVariable = value;
      
    • 通过*操作符解引用指针并访问对象的成员:
      (*ptr).memberFunction();
      (*ptr).memberVariable = value;
      
  3. 转移拥有权:

    • 通过将std::unique_ptr赋值给其他std::unique_ptr来转移拥有权:
      std::unique_ptr<Type> ptr2 = std::move(ptr);
      
    • std::unique_ptr作为返回值返回,从而转移拥有权:
      std::unique_ptr<Type> someFunction();
      

    请注意,一旦拥有权转移给其他std::unique_ptr,原始指针将变为nullptr

  4. 手动释放对象:

    • 如果不再需要对象,可以通过将std::unique_ptr赋值为nullptr来手动释放对象并释放内存:
      ptr.reset();
      
    • std::unique_ptr离开其作用域时,它会自动释放对象。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值