Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C++11新特性:enable_shared_from_this解决大问题

C++11新特性:enable_shared_from_this解决大问题

作者头像
CPP开发前沿
发布于 2022-06-04 09:27:56
发布于 2022-06-04 09:27:56
5.9K04
代码可运行
举报
文章被收录于专栏:CPP开发前沿CPP开发前沿
运行总次数:4
代码可运行

作为一老码农,从看的第一本C语言书开始就不断地被灌输一种思想:谨慎使用指针,使用一定要遵循谁申请谁释放的原则。后来又学习C++,同样好像所有关于C/C++的书籍都在不断地重复着一件事:指针很灵活,也很难管理,谁用谁知道

实际上,在使用现代C++之前,我们也是这么做的,做代码走查的时候不管别的,先看下有没有使用new或者malloc。如果有就直接向后看。检查有没有delete或者free,是不是成对出现。当然,不管有没有,做为一个被职场磨了棱角的人都会在重复或者听别人重复着:自己申请的资源一定要自己管理,自己做的事情要自己负责,做一个负责任的人

幸运的是这种情况并没有持续太久,C++11推出了智能指针,不得不承认,了解后才感到自己的知识有限。居然想不出一个华美的词进行赞扬,只能说一句:我~草~牛逼呀!写代码时终于不用手动分配内存,时刻准备着资源的释放和清理了,再也不用担心我的程序有内存泄漏了~。我的天哪!

可是,对一种事务的过分追捧同时也伴随着另外一件事,写代码时因为过于嚣张,我的代码有bug了,很难相信呀……就简单的几行代码而已。为了证明它真的很简单,代码现在就贴出来:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main()
{
  int* pt = new int();
  shared_ptr<int> _p1(pt);
  shared_ptr<int> _p2(pt);
  std::cout << "_p1.use_count() = " << _p1.use_count() << std::endl;
  std::cout << " _p2.use_count() = " << _p2.use_count() << std::endl;
  return 0;
}

运行后代码输出了结果:

同时也报出了异常~~~~

从程序上看,代码中定义了两个智能指针变量,按照理解,智能指针的引用计数应该是2,但是实际输出的却是1,而这里也是程序结束时触发异常报错的原因:重复释放!而这同时也说明:智能共享指针不能够直接从this对象进行构造。

好了。现在开始进入正题。聊聊我们今天的重点:enable_shared_from_this。enable_shared_from_this从本质上来说解决了不能直接冲this对象构造智能指针的问题,但是使用时也需要注意,既返回的智能智能必须要通过shared_from_this()获取,当然也可以不用,但是从大家的开发经验来看,真心劝解不要盲目自大。

1 enable_shared_from_this如何使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class MyCar:public std::enable_shared_from_this<MyCar>
{
public:
  shared_ptr<MyCar> get_ptr() {
    return shared_from_this();
  }
  ~MyCar() {
    std::cout << "free ~Mycar()" << std::endl;
  }
private:

};

int main()
{
  MyCar* _myCar = new MyCar();
  shared_ptr<MyCar> _myCar1(_myCar);
  shared_ptr<MyCar> _myCar2 = _myCar->get_ptr();
  std::cout << _myCar1.use_count() << std::endl;
  std::cout << _myCar2.use_count() << std::endl;
  return 0;
}

上面的代码定义了一个类,然后继承了std::enable_shared_from_this。在类中提供了一个获取智能指针的方法。在main函数中使用时,同样,也是先定义一个类的指针,然后初始化了_myCar1,_myCar2则是通过类中提供的获取指针的方法获取了智能指针对象。运行结果如下:

结果也和预期的一致,通过使用std::enable_shared_from_this。两次智能指针的使用增加了共享指针的引用次数。程序退出时也只进行了一次析构。从运行结果来看,使用std::enable_shared_from_this解决了:不能通过原指针增加引用次数的问题

2、使用enable_shared_from_this需要注意的事

在一开始编写上面的代码时,代码是这么写的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
nt main()
{
  MyCar* _myCar = new MyCar();
  shared_ptr<MyCar> _myCar1 = _myCar->get_ptr();
  shared_ptr<MyCar> _myCar2 = _myCar->get_ptr();
  std::cout << _myCar1.use_count() << std::endl;
  std::cout << _myCar2.use_count() << std::endl;
  return 0;
}

看第四行:这里不是对智能指针进行构造,而是和_myCar2一样通过_myCar->get_ptr()的方法进行赋值,这样写从语法上是没有错误的。但是运行时却报错了。报错的内容是:

如上图所示,异常位置是在弱指针处,从C++书籍中可以知道,弱指针实际上是智能共享指针的伴随指针,它主要负责监控智能指针的声明周期,弱指针本身的构造和析构都不会对引用计数进行修改,纯粹是作为一个助手监视shared_ptr管理的资源是否存在。

弱指针的初始化是通过智能指针的构造函数来实现的,在上面的代码中对智能指针初始化时并没有使用构造函数的方式,因为弱指针是没有正常进行初始化的。也因为此,在运行上面的程序时,编译器抛出了异常。

因此,在使用上述方法时必须要使用智能指针的构造函数先初始化一个智能指针。

除此之外,在使用std::enable_shared_from_this时要保证类是公有继承的,至于为什么不能私有继承或者受保护的继承,欢迎大家留言评论。

3 std::enable_shared_from_this和share_ptr的关系

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// CLASS TEMPLATE enable_shared_from_this
template <class _Ty>
class enable_shared_from_this { // provide member functions that create shared_ptr to this
public:
    using _Esft_type = enable_shared_from_this;

    _NODISCARD shared_ptr<_Ty> shared_from_this() { // return shared_ptr
        return shared_ptr<_Ty>(_Wptr);
    }

    _NODISCARD shared_ptr<const _Ty> shared_from_this() const { // return shared_ptr
        return shared_ptr<const _Ty>(_Wptr);
    }

    _NODISCARD weak_ptr<_Ty> weak_from_this() noexcept { // return weak_ptr
        return _Wptr;
    }

    _NODISCARD weak_ptr<const _Ty> weak_from_this() const noexcept { // return weak_ptr
        return _Wptr;
    }

protected:
    constexpr enable_shared_from_this() noexcept : _Wptr() {}

    enable_shared_from_this(const enable_shared_from_this&) noexcept : _Wptr() {
        // construct (must value-initialize _Wptr)
    }

    enable_shared_from_this& operator=(const enable_shared_from_this&) noexcept { // assign (must not change _Wptr)
        return *this;
    }

    ~enable_shared_from_this() = default;

private:
#if _HAS_IF_CONSTEXPR
    template <class _Yty>
    friend class shared_ptr;
#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv
    template <class _Other, class _Yty>
    friend void _Enable_shared_from_this1(const shared_ptr<_Other>& _This, _Yty* _Ptr, true_type) noexcept;
#endif // _HAS_IF_CONSTEXPR

    mutable weak_ptr<_Ty> _Wptr;
};

从上面的代码中可以看出,share_ptr是std::enable_shared_from_this的友元类,实际上在上面的代码中,对智能指针进行初始化时除了完成_myCar1的初始化外,还做了额外的工作,既通过前面std::enable_shared_from_this的继承使得后面对智能指针进行初始化时同时初始化了弱指针。

写在最后:enable_shared_from_this这个题目在草稿箱待了很久了。今天终于写完了。心情顿时爽了很多。当然,人无完人,不可否认也会存在问题,欢迎大家批评指正。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-04-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CPP开发前沿 微信公众号,前往查看

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
现代 C++:一文读懂智能指针
简单说,当我们独占资源的所有权的时候,可以使用 std::unique_ptr 对资源进行管理——离开 unique_ptr 对象的作用域时,会自动释放资源。这是很基本的 RAII 思想。
linjinhe
2020/06/22
1.4K0
C++ enable_shared_from_this 具体实现
C++ 中使用 std::shared_ptr 智能指针不当有可能会造成循环引用,因为 std::shared_ptr 内部是基于引用计数来实现的, 当引用计数为 0 时,就会释放内部持有的裸指针。但是当 a 持有 b, b 也持有 a 时,相当于 a 和 b 的引用计数都至少为 1,因此得不到释放,RAII 此时也无能为力。这时就需要使用 weak_ptr 来打破循环引用。
JoeyBlue
2022/11/21
1.1K0
C++模版笔记(2)
enable_if<> 的作用是满足条件后可以使用模版推导,基于SFINAE(substitution failure is not an error), 这样可以按照条件控制是否使用模版。
一只小虾米
2022/10/25
5120
灵魂拷问std::enable_shared_from_this,揭秘实现原理
在C++编程中,使用智能指针是一种安全管理对象生命周期的方式。std::shared_ptr是一种允许多个指针共享对象所有权的智能指针。然而,当一个对象需要获取对自身的shared_ptr时,传统的方法可能导致未定义行为。为了解决这个问题,C++引入了std::enable_shared_from_this类,本文将深入探讨其基础知识、使用案例以及内部实现。
公众号guangcity
2023/11/22
3.1K0
灵魂拷问std::enable_shared_from_this,揭秘实现原理
【C++】简单实现C++11的三种智能指针
本篇是尝试对C++11的三种智能指针(unique_ptr, shared_ptr, weak_ptr)进行的复现结果, 智能指针的复现在面试中经常考到, 需要好好熟悉.
ZifengHuang
2022/11/18
2.1K0
【C++】简单实现C++11的三种智能指针
【C++11】 使用C++11解决内存泄露--智能指针
众所周知,C#和java中不需要开发人员自己释放内存,对象引用计数为零后.Net和Java虚拟机会对对象进行自动回收,从而防止内存泄露;但是C++语言中,在堆上分配的内存必须自己去管理,不用的时候要自己释放,如果管理不当就可能会出现内存泄露。
CPP开发前沿
2021/11/16
7440
详解 C++ 11 中的智能指针
C/C++ 语言最为人所诟病的特性之一就是存在内存泄露问题,因此后来的大多数语言都提供了内置内存分配与释放功能,有的甚至干脆对语言的使用者屏蔽了内存指针这一概念。这里不置贬褒,手动分配内存与手动释放内存有利也有弊,自动分配内存和自动释放内存亦如此,这是两种不同的设计哲学。有人认为,内存如此重要的东西怎么能放心交给用户去管理呢?而另外一些人则认为,内存如此重要的东西怎么能放心交给系统去管理呢?在 C/C++ 语言中,内存泄露的问题一直困扰着广大的开发者,因此各类库和工具的一直在努力尝试各种方法去检测和避免内存泄露,如 boost,智能指针技术应运而生。
范蠡
2019/10/25
2.8K0
详解 C++ 11 中的智能指针
掌握C++中智能指针的综合指南:深入现代内存管理
智能指针主要解决以下问题: (1)内存泄漏:内存手动释放,使用智能指针可以自动释放。 (2)共享所有权指针的传播和释放,比如多线程使用同一个对象时析构问题。
Lion 莱恩呀
2024/10/28
3780
掌握C++中智能指针的综合指南:深入现代内存管理
C++ 新特性学习(一) -- 概述+智能指针(smart_ptr)
C++ 0x/11 终于通过了,真是个很爽的消息。于是乎我决定对新的东西系统学习一下。
owent
2018/08/01
6040
一文彻底掌握智能指针!
大家好,今天继续分享一篇基础的智能指针的使用,在分享这篇之前,大家可以看之前分享的两种智能指针:C++智能指针学习(一),今天我们来分享剩下的两个智能指针:
用户6280468
2022/03/18
1.6K0
C++ 智能指针最佳实践&源码分析
作者:lucasfan,腾讯 IEG Global Pub.Tech. 客户端工程师 智能指针在 C++11 标准中被引入真正标准库(C++98 中引入的 auto_ptr 存在较多问题),但目前很多 C++开发者仍习惯用原生指针,视智能指针为洪水猛兽。但很多实际场景下,智能指针却是解决问题的神器,尤其是一些涉及多线程的场景下。本文将介绍智能指针可以解决的问题,用法及最佳实践。并且根据源码分析智能指针的实现原理。 一、为什么需要使用智能指针 1.1 内存泄漏 C++在堆上申请内存后,需要手动对内存进行
腾讯技术工程官方号
2021/12/21
1.9K0
c++11新特性之智能指针
shared_ptr使用了引用计数,每一个shared_ptr的拷贝都指向相同的内存,每次拷贝都会触发引用计数+1,每次生命周期结束析构的时候引用计数-1,在最后一个shared_ptr析构的时候,内存才会释放。
C语言与CPP编程
2020/12/02
8440
再探 智能指针
1、一个裸的指针不要用两个shared_ptr管理,unique_ptr也是,它们都会认为自己独占这个资源,你等释放的时候试试看。
看、未来
2021/10/20
3030
C++雾中风景14:CRTP, 模板的黑魔法
C++11 引入了一个典型的CRTP的类:std::enable_shared_from_this 当我们有类需要被智能指针share_ptr管理,且需要通过类的成员函数里需要把当前类对象包装为智能指针传递出一个指向自身的share_ptr时。在这种情况下类就需要通过继承enable_shared_from_this,通过父类的成员函数shared_from_this来获取指向该类的智能指针。
HappenLee
2020/07/13
1.7K0
C++智能指针「建议收藏」
以上代码运行时,由于ptr2拷贝构造时默认是浅拷贝,两个对象底层的裸指针指向同一份资源,对象析构时,会出现同一资源释放两次的错误(释放野指针),这里需要解决两个问题:
全栈程序员站长
2022/08/31
5350
C++智能指针「建议收藏」
实现一个strong_rc_ptr(非线程安全版本的std::shared_ptr)
我们的新项目有个比较复杂的全区全服交易行系统,其中搜索和推荐是高实时性全区服多维度排序的,并且要支持比较复杂的标签交集查询和属性范围查询的自由组合。 当有订单发生变化时,它不仅仅会影响全服状态下搜索和推荐条件的结果变化,也会同时影响商品维度的聚合,交易行层面的数据聚合。
owent
2024/10/09
1550
【C++11新特性】 C++11智能指针之weak_ptr
我们知道shared_ptr是采用引用计数的智能指针,多个shared_ptr实例可以指向同一个动态对象,并维护了一个共享的引用计数器。
音视频开发进阶
2020/06/11
1.7K0
C++智能指针的正确使用方式
C++11中推出了三种智能指针,unique_ptr、shared_ptr和weak_ptr,同时也将auto_ptr置为废弃(deprecated)。
cyhone
2019/10/05
10.1K0
深入理解 C++11 智能指针:独占、共享与弱引用的完美管理
unique_ptr是最常用的一种智能指针,它确保一个指针在同一时刻只能有一个所有者。当unique_ptr超出作用域时,它所持有的资源会自动被销毁。
用户11286421
2025/03/24
3520
深入理解 C++11 智能指针:独占、共享与弱引用的完美管理
C++17中weak_from_this详解
weak_from_this 是 std::enable_shared_from_this 类模板的一个成员函数,其核心作用是获取当前对象的 std::weak_ptr。与 shared_from_this 不同,weak_from_this 返回的 std::weak_ptr 不会增加对象的引用计数。这一特性使得它在处理对象生命周期管理时具有独特的优势。
码事漫谈
2025/02/01
890
C++17中weak_from_this详解
相关推荐
现代 C++:一文读懂智能指针
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档