前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++11新特性:enable_shared_from_this解决大问题

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

作者头像
CPP开发前沿
发布2022-06-04 17:27:56
2.5K0
发布2022-06-04 17:27:56
举报
文章被收录于专栏:CPP开发前沿CPP开发前沿

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

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

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

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

代码语言:javascript
复制
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
复制
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
复制
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
复制
// 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 删除。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档