C++进阶STL-智能指针

本文介绍了C++中的智能指针,包括std::auto_ptr(已弃用)、std::unique_ptr、std::shared_ptr和std::weak_ptr。智能指针用于自动管理内存,避免内存泄露。其中,unique_ptr是独占式,shared_ptr允许多个指针共享,weak_ptr则用于解决shared_ptr的循环引用问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考1
参考2

介绍

在使用智能指针之前,一般都是用new和delete来进行内存的管理,但是一旦忘记delete,这样容易造成内存泄露。从而导致智能指针的出现,它只需要你创建,之后就不需要你管,也不需要你手动释放,到该释放的地方,它会自动释放。

  • 原理:其实智能智能是一个模板类,内部有指向模板的一个指针,释放使用析构函数进行,所以这是自动的过程。定义在<memory> 命名空间 std

四种智能指针

std::auto_ptr(已经被C++11弃用)

使用的时候会给警告:is deprecated

  • 注意:不建议使用,但是如果使用,记住它是独占式,将p2 = p1 ,那么p1 则是nullptr,如果再通过p1去操作,程序会直接崩溃


std::unique_ptr

  • 介绍:正如名字一样,它也是独占式的指针,尝试将它复制给其他指针会编译报错,但是可以通过std::move()进行操作,操作之后原先的指针也不能用,这也解释了unique的含义。
    std::unique_ptr<Person> p1(new Person(1));
    int id = p1->GetId();

    // std::unique_ptr<Person> p2 = p1; 报错
    std::unique_ptr<Person> p2 = std::move(p1);

    id = p2->GetId();
    cout << id << endl;

    // id = p1->GetId(); p1交给p2之后,便不能用了 

补充:boost库的 boost::scoped_ptr 也是一个独占式的智能指针,但是它不允许转移所有权,从始而终都只对一个资源负责,它更安全谨慎,但是应用的范围也更狭窄



std::shared_ptr

  • 介绍:shared_ptr 是一种共享式所有权的指针,它允许多个指针指向同一个对象,既然它提供多个指针指向同一个对象的功能,但是到底由谁来释放?我们想的肯定是由最后一个指针来进行释放工作,如何知道当前的已经是最后一个指针了?所以引入了额外开销:计数
  • shared_ptr 除了拥有一个指向目标对象的指针外,还有一个指向 “计数区域(里面有计数器)” 的指针, 结构大概这样:
    在这里插入图片描述
    当每次进行复制shared_ptr的时候,通过ptr2间接的操作counter+1,某处shared_ptr“释放”的时候,counter-1,直到0,才去真正释放object对象和counter区域
{ 
    std::shared_ptr<Person> p1(new Person(1)); // counter:1

    int id = 1;
    while(id--)
    {
	std::shared_ptr<Person> p2 = p1; //counter:2
    } // counter:1
    
    std::shared_ptr<Person> p3 = p1; // counter:2


} // counter:0


缺陷:存在循环引用计数不正常(采用weak_ptr可以解决此问题),详细见参考1,2



std::weak_ptr

  • weak_ptr 是为了辅助shared_ptr而存在,在上面shared_ptr 前提条件下,在counter里面加入weak_counter计数器,所以有了两个计数器(shared_counter, weak_counter)


    在这里插入图片描述
  • weak_ptr存在的机制依赖于以下几个条件:
  1. weak_ptr 可由另一个weak_ptr或者shared_ptr构造
  2. weak_ptr的构造和析构不会引起shared_count的增加或减少,只会引起weak_count的增加或减少。
  3. 被管理资源的释放只取决于shared_counter计数,当shared_counter计数为0,才会释放被管理资源。即weak_ptr不控制资源的生命周期
  4. 计数区域的释放却取决于shared计数和weak计数,当两者均为0时,才会释放计数区域

  • 可以利用weak_ptr的成员函数use_count() 来查看share_counter的计数值
int main(void)
{
    std::shared_ptr<Person> p1(new Person(1)); // counter:1
    std::weak_ptr<Person> pp1 = p1;
    cout << pp1.use_count() << endl;

    int id = 1;
    while(id--)
    {
	std::shared_ptr<Person> p2 = p1; //counter:2
	cout << pp1.use_count() << endl;


    } // counter:1
    
    cout << pp1.use_count() << endl;
    std::shared_ptr<Person> p3 = p1; // counter:2
    cout << pp1.use_count() << endl;

    return 0;
} // counter:0


执行结果:
:


  • weak_ptr 没有重载 -> 和* 符号,所以没有办法进行操作,但是可以使用lock()获得一个可用的shared_ptr, 如果没有可用的shared_ptr,返回的是空指针。
    std::shared_ptr<Person> p1(new Person(1));

    std::weak_ptr<Person> p2 = p1;
    //id = p2->GetId(); // 错误,weak_ptr 没有重载->和*
    
    std::shared_ptr<Person> p3 = p2.lock();
    int id = p3->GetId();
    cout << id << endl;



  • weak_ptr 可以打破shared_ptr的循环引用计数错误的问题,见参考1,2


如何选取智能指针

  1. 如果需要多个指针指向同一个对象,使用shared_ptr
  2. 如果某一个对象规定只有唯一的指针来进行操作,使用unique_ptr
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值