专栏首页架构说使用 C++ 智能指针遇到的坑

使用 C++ 智能指针遇到的坑

使用 C++ 智能指针遇到的坑

阅读收益

  • 智能指针目的就是代替原始指针,那么问题来了,原始指针都可以用智能指针代替吗?不能
  • 智能指针 unique_ptr、shared_ptr 和 weak_ptr三个,那么问题来了 一个不能代替全部吗?不能
  • shared_ptr vs weak_ptr

shared_ptr 使用条件:有多个使用者共同使用同一个对象

  1. 假如 一个类成员 是指针,这个普通类 可以被值拷贝。类表值语义,被多次被copy和访问和销毁。一个类成员 是指针是浅拷贝,避免更大开销 可以使用shared_ptr
  2. 多线程多读少写 读写一致性 利用shared_ptr和互斥锁来模拟读写锁

shared_ptr 不使用条件(需要改写):双向链表

  1. 用weak_ptr解决shared_ptr的环形引用问题(避免内存泄露,无法调用析构函数)

unique_ptr 不使用条件(需要改写):容器里存放指针。指针reszie 大小

  • unique_ptr 剩下全部场景都可以用代替吗?unique_ptr默认不能copy,如果一次使用 禁止拷class
  • 虽然move实现拷贝,unique_ptr原来指针为null,有core的风险。解决办法:实现智能指针的深度拷贝。

开始

C++11 中推出了三种智能指针,unique_ptr、shared_ptr 和 weak_ptr,同时也将 auto_ptr 置为废弃 (deprecated)。

但是在实际的使用过程中,很多人都会有这样的问题:

  • 不知道三种智能指针的具体使用场景
  • 无脑只使用 shared_ptr
  • 认为应该禁用 raw pointer(裸指针,即 Widget * 这种形式),全部使用智能指针

对象所有权

在编程语言中,对堆对象的内存管理是一个麻烦又复杂的问题。一不小心就会带来问题(堆上数据通过指针来访问。)

C++里多个变量指向同一块内存导致重复释放。本文简单探讨一下关于对象所有权的问题

  • 首先需要理清楚的概念就是对象所有权的概念

明白了对象所有权,我们才可以正确管理好对象生命周期和内存问题。

对象的所有权意味着当我们分配一个对象的时候,谁持有这个对象的所有权

Guru Questions 1(大师级问题)

既然智指针,能避免内存泄漏问题,

能代替all场景的原始指针吗?,

为什么发明三个 而不是一个,来一统天下。

  • unique_ptr 代替全部原始指针吗?

答:不是的,如果使用不当会造成 core 或者 不执行析构函数。

在类的成员,或者函数参数传递。

boost\smart_ptr\weak_ptr.hpp

如果 weak_ptr 指向某一 shared_ptr 指针拥有的堆内存, 则 weak_ptr 也指向该块存储空间(可以访问,但无所有权)

weak_ptr:

element_type * px;            // contained pointer
boost::detail::weak_count pn; // reference counter
    
weak_count & operator= (shared_count const & r) BOOST_SP_NOEXCEPT
    {
        sp_counted_base * tmp = r.pi_;

        if( tmp != pi_ )
        {
            if(tmp != 0) tmp->weak_add_ref();
            if(pi_ != 0) pi_->weak_release();
            pi_ = tmp;
        }

        return *this;
    }

如果 weak_ptr 指向某一 shared_ptr 指针拥有的堆内存, 则 weak_ptr 也指向该块存储空间(可以访问,但无所有权)

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

int main()
{
    std::shared_ptr<int> sp1(new int(10));
    std::shared_ptr<int> sp2(sp1);
    std::weak_ptr<int> wp(sp2);
    //输出和 wp 同指向的 shared_ptr 类型指针的数量
    cout << wp.use_count() << endl;
    //释放 sp2
    sp2.reset();
    cout << wp.use_count() << endl;
    //借助 lock() 函数,返回一个和 wp 同指向的 shared_ptr 类型指针,获取其存储的数据
    cout << *(wp.lock()) << endl;
    return 0;
}

程序执行结果为:2 1 10

shared_ptr.hpp

    element_type * px;                 // contained pointer
    boost::detail::shared_count pn;    // reference counter

敲黑板:shared_ptr 放到一个类中,这个类值传递,shared_ptr值义 ,不考虑内部的copy问题。但是但是双向链表成员 不能用shared_ptr表示

  • 写代码验证你结果:shared_ptr 转变成 weak_ptr 不增加 shared_ptr引用计数。不回造成死循环。
#include<iostream>
#include<memory>
using namespace std;

struct Node
{
    int _value;

    //shared_ptr<Node> _next;
    //shared_ptr<Node> _prev;

    weak_ptr<Node> _next;
    weak_ptr<Node> _prev;

    ~Node()
    {
        cout << " ~Node()  "<<_value << endl;
    }
    Node( int input)
    {
        _value = input;
    }
};



int main()
{
    shared_ptr<Node> sp1(new Node(1));
    shared_ptr<Node> sp2(new Node(2));

    sp1->_next = sp2; //为什么:shared_ptr 转变成 weak_ptr 不增加 shared_ptr引用计数呢?
    sp2->_prev = sp1; //为什么:shared_ptr 转变成 weak_ptr 不增加 shared_ptr引用计数呢?

    cout<<sp1.use_count()<<endl; //引用计数-->1 不是 2

    cout << sp2.use_count() << endl; //引用计数-->1 不是 2

    return 0;
}
//https://blog.csdn.net/qq_36430106/article/details/89441856

敲黑板:

对象的延迟销毁。陈硕在《Linux 多线程服务器端编程》中提到,当一个对象的析构非常耗时, 甚至影响到了关键线程的速度。可以使用 BlockingQueue<std::shared_ptr> 将对象转移到另外一个线程中释放, 从而解放关键线程。

敲黑板:

  1. 利用shared_ptr和互斥锁来模拟读写锁
  2. 用weak_ptr解决shared_ptr的环形引用问题

unique_ptr

遇到的坑

//用了unique_ptr为什么会core, 这是unique_ptrbug吗?

void TestAutoPtr5() 
{
    std::cout << "TestAutoPtr5 Test" << std::endl;
    std::vector<std::unique_ptr<SimpleTest>> vc;
    vc.push_back(std::unique_ptr<SimpleTest>(new SimpleTest(5)));
    vc.push_back(std::unique_ptr<SimpleTest>(new SimpleTest(6)));
    vc.push_back(std::unique_ptr<SimpleTest>(new SimpleTest(7)));

    // 1-----
    for (std::vector<std::unique_ptr<SimpleTest>>::iterator iter = vc.begin();
         iter != vc.end(); iter++)
    {
        (*iter)->DoSomething();
    }

    // 2-----
    vc.resize(5);
    //可看出智能指针尽量不要指向vector容器类型,因为当vector扩容时,智能指针便不再生效,引起程序的崩溃或未定义的行为。
    for (std::vector<std::unique_ptr<SimpleTest>>::iterator iter = vc.begin();
         iter != vc.end(); iter++)
    {
        (*iter)->DoSomething();
    }
}

本文分享自微信公众号 - 架构说(JiaGouS),作者:王传义

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-07-31

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • c++基础 使用智能指针

    三个智能指针模板(auto_ptr、unique_ptr和shard_ptr)都定义了类似指针的对象(c++11已将auto_ptr摒弃),可以将new获得(直...

    lpxxn
  • C++智能指针的正确使用方式

    C++11中推出了三种智能指针,unique_ptr、shared_ptr和weak_ptr,同时也将auto_ptr置为废弃(deprecated)。

    cyhone
  • 目录1.智能指针的作用2.智能指针的使用3.智能指针的设计和实现

    C++程序设计中使用堆内存是非常频繁的操作,堆内存的申请和释放都由程序员自己管理。程序员自己管理堆内存可以提高了程序的效率,但是整体来说堆内存的管理是麻烦的,...

    用户1215536
  • 详解 C++ 11 中的智能指针

    C/C++ 语言最为人所诟病的特性之一就是存在内存泄露问题,因此后来的大多数语言都提供了内置内存分配与释放功能,有的甚至干脆对语言的使用者屏蔽了内存指针这一概念...

    范蠡
  • 使用 SpringBoot 的 CommandLineRunner 遇到的坑

    来源:blog.csdn.net/zwq_zwq_zwq/article/details/81059017

    Java小咖秀
  • C++核心准则R.37: 不要使用从破损的智能指针​获取的指针或引用

    Violating this rule is the number one cause of losing reference counts and findi...

    面向对象思考
  • Kotlin中使用Dagger2可能遇到的坑解决

    Dagger2是一款基于Java注解,在编译阶段完成依赖注入的开源库,主要用于模块间解耦,方便进行测试。

    砸漏
  • 使用TabLayout遇到的几个坑

    提莫队长
  • k8s上使用jenkins遇到的坑

    最近几天,遇到了一个让我百思不得其解的问题,那就是我使用jenkins pipeline进行简单的测试时,两个stage之间需要1分钟左右的切换时...

    没有故事的陈师傅
  • C++ RCSP智能指针简单实现与应用

    智能指针的实现代码来源博客:《http://blog.csdn.net/to_be_better/article/details/53570910》

    jianghaibobo
  • C++ 智能指针(unique_ptr, shared_ptr)的源码分析

    在博文https://blog.csdn.net/qq_27717921/article/details/82940519已经介绍了unique_ptr和sha...

    张凝可
  • Android 使用so库的遇到的坑

    做Android开发会遇到各种各样的问题,遇到问题不可怕,解决了并且知道为什么,下次遇到能马上解决就好了,今天要说的就是这个so库的使用采坑了。

    晨曦_LLW
  • 使用Python操作redis遇到的坑 转

    基于Python3.4,往redis里插入数据后再读出来时所有键与值都是byte类型的,就是说如果你要使用这些值全部都得转换编码!想想就崩溃!但又想想肯定会有简...

    双面人
  • 【kafka异常】使用Spring-kafka遇到的坑

    有想进滴滴LogI开源用户群的加我个人微信: jjdlmn_ 进群(备注:进群) 群里面主要交流 kakfa、es、agent、LogI-kafka-mana...

    石臻臻的杂货铺[同名公众号]
  • C++ 引用计数技术及智能指针的简单实现

    Tencent JCoder
  • php 使用函数中遇到的坑之----strpos

    strpos — 查找字符串首次出现的位置 mixed strpos ( string $haystack , mixed $needle [, int $of...

    joshua317
  • php 使用函数中遇到的坑之----list

    1. list 把数组中的值赋给一些变量 <?php $info = array('coffee', 'brown', 'caffeine'); // 列出所有...

    joshua317
  • Retrofit--记使用Retrofit时遇到的一个坑

    版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/lyhhj/article/details/52...

    Hankkin
  • 使用strptime函数时遇到的一个坑

    做新专辑排序的需求时,需要对专辑的时间进行排序,由于目前该字段是字符串类型的日期,在排序函数中要转成标准的UNIX时间戳来进行对比,大概代码如下:

    jackieluo

扫码关注云+社区

领取腾讯云代金券