前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 C++ 智能指针遇到的坑

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

作者头像
程序员小王
发布2021-08-13 10:36:16
2.4K0
发布2021-08-13 10:36:16
举报
文章被收录于专栏:架构说架构说

使用 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 也指向该块存储空间(可以访问,但无所有权)

代码语言:javascript
复制
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 也指向该块存储空间(可以访问,但无所有权)

代码语言:javascript
复制
#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

代码语言:javascript
复制

    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引用计数。不回造成死循环。
代码语言:javascript
复制
#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

遇到的坑

代码语言:javascript
复制
//用了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();
    }
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-07-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Offer多多 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用 C++ 智能指针遇到的坑
    • 阅读收益
      • shared_ptr 使用条件:有多个使用者共同使用同一个对象
      • shared_ptr 不使用条件(需要改写):双向链表
      • unique_ptr 不使用条件(需要改写):容器里存放指针。指针reszie 大小
    • 开始
      • 对象所有权
    • Guru Questions 1(大师级问题)
      • boost\smart_ptr\weak_ptr.hpp
      • shared_ptr.hpp
    • unique_ptr
      • 遇到的坑
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档