C++里std::enable_shared_from_this是干什么用的?

std::enable_shared_from_this使用场景 在很多场合,经常会遇到一种情况,如何安全的获取对象的this指针,一般来说我们不建议直接返回this指针,可以想象下有这么一种情况,返回的this指针保存在外部一个局部/全局变量,当对象已经被析构了,但是外部变量并不知道指针指向的对象已经被析构了,如果此时外部使用了这个指针就会发生程序奔溃。既要像指针操作对象一样,又能安全的析构对象,很自然就想到,智能指针就很合适!

那么智能指针如何使用呢?现在我们来看一段代码。

#include #include

class Widget{ public: Widget(){ std::cout << "Widget constructor run" << std::endl; } ~Widget(){ std::cout << "Widget destructor run" << std::endl; }

std::shared_ptr<Widget> GetSharedObject(){
    return std::shared_ptr<Widget>(this);
}

};

int main() { std::shared_ptr p(new Widget()); std::shared_ptr q = p->GetSharedObject();

std::cout << p.use_count() << std::endl;
std::cout << q.use_count() << std::endl;

return 0;

} 编译运行后程序输出如下:

Widget constructor run 1 1 Widget destructor run Widget destructor run 22:06:45: 程序异常结束。 从输出我们可以看到,调用了一次构造函数,却调用了两次析构函数,很明显这是不正确的。而std::enable_shared_from_this正是为了解决这个问题而存在。

std::enable_shared_from_this原理和实战 前面我们说使用std::enable_shared_from_this能解决安全获取this指针的问题。在使用之前,我们先来了解下std::enable_shared_from_this是什么?为什么能解决这个问题?std::enable_shared_from_this定义如下:

template class _LIBCPP_TEMPLATE_VIS enable_shared_from_this { mutable weak_ptr<_Tp> _weak_this; protected: _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR enable_shared_from_this() _NOEXCEPT {} _LIBCPP_INLINE_VISIBILITY enable_shared_from_this(enable_shared_from_this const&) _NOEXCEPT {} _LIBCPP_INLINE_VISIBILITY enable_shared_from_this& operator=(enable_shared_from_this const&) _NOEXCEPT {return *this;} _LIBCPP_INLINE_VISIBILITY ~enable_shared_from_this() {} public: _LIBCPP_INLINE_VISIBILITY shared_ptr<_Tp> shared_from_this() {return shared_ptr<_Tp>(_weak_this);} _LIBCPP_INLINE_VISIBILITY shared_ptr<_Tp const> shared_from_this() const {return shared_ptr(_weak_this);}

#if _LIBCPP_STD_VER > 14 _LIBCPP_INLINE_VISIBILITY weak_ptr<_Tp> weak_from_this() _NOEXCEPT { return _weak_this; }

_LIBCPP_INLINE_VISIBILITY
weak_ptr<const _Tp> weak_from_this() const _NOEXCEPT
    { return __weak_this_; }

#endif // _LIBCPP_STD_VER > 14

template <class _Up> friend class shared_ptr;

}; std::enable_shared_from_this是模板类,内部有个_Tp类型weak_ptr指针,调用shared_from_this成员函数便可获取到_Tp类型智能指针,从这里可以看出,_Tp类型就是我们的目标类型。再来看看std::enable_shared_from_this的构造函数都是protected,因此不能直接创建std::enable_from_shared_from_this类的实例变量,只能作为基类使用。因此使用方法如下代码所示:

#include #include

class Widget : public std::enable_shared_from_this{ public: Widget(){ std::cout << "Widget constructor run" << std::endl; } ~Widget(){ std::cout << "Widget destructor run" << std::endl; }

std::shared_ptr<Widget> GetSharedObject(){
    return shared_from_this();
}

};

int main() { std::shared_ptr p(new Widget()); std::shared_ptr q = p->GetSharedObject();

std::cout << p.use_count() << std::endl;
std::cout << q.use_count() << std::endl;

return 0;

} 这里为什么要创建智能指针p而不是直接创建裸指针p?根本原因在于std::enable_shared_from_this内部的weak_ptr,若只是创建裸指针p,那么p被delete后仍然面对不安全使用内部this指针问题。因此p只能被定义为智能指针。当p被定义为shared_ptr智能指针后,p指针引用计数是1(weak_ptr不会增加引用计数),再通过shared_from_this获取内部this指针的智能指针,则p的引用计数变为2。

现编译运行输出如下:

Widget constructor run 2 2 Widget destructor run 正确的返回了智能指针,p和q的引用计数都是2,且只调用了一次构造函数和析构函数,不会错误的析构对象多次。

全部评论

相关推荐

牛客小菜鸡66:boss里面,招人的叫老板,找工作的叫牛人
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
正在热议
更多
# 你的mentor是什么样的人? #
4336次浏览 32人参与
# 你觉得mentor喜欢什么样的实习生 #
10601次浏览 297人参与
# 智慧芽求职进展汇总 #
18243次浏览 108人参与
# 帮我看看,领导说这话什么意思? #
6524次浏览 26人参与
# 26届秋招公司红黑榜 #
12894次浏览 43人参与
# 怎么给家人解释你的工作? #
1546次浏览 16人参与
# 平安产险科技校招 #
2419次浏览 0人参与
# 没有家庭托举的我是怎么找工作的 #
12561次浏览 160人参与
# 求职低谷期你是怎么度过的 #
5368次浏览 93人参与
# 实习必须要去大厂吗? #
146772次浏览 1541人参与
# 从哪些方向判断这个offer值不值得去? #
6696次浏览 95人参与
# 同bg的你秋招战况如何? #
158849次浏览 927人参与
# 度小满求职进展汇总 #
10174次浏览 53人参与
# 校招泡的最久的公司是哪家? #
4711次浏览 23人参与
# 面试紧张时你会有什么表现? #
1764次浏览 21人参与
# 你有哪些缓解焦虑的方法? #
37191次浏览 835人参与
# 你喜欢工作还是上学 #
77606次浏览 860人参与
# 入职第一天,你准备什么时候下班 #
85505次浏览 467人参与
# 秋招想进国企该如何准备 #
97734次浏览 487人参与
# 简历无回复,你会继续海投还是优化再投? #
103605次浏览 819人参与
# 机械人的工作环境真的很差吗 #
25065次浏览 119人参与
# 独居后,你的生活是更好了还是更差了? #
28142次浏览 263人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务