#include <memory>
#include <iostream>
#include <cstdio>
#pragma optimize("",off)
char* g_temp_test_valid = nullptr;
std::shared_ptr<char[]> getMem() {
std::shared_ptr<char[]> pOut(new char[10]);
strcpy_s(pOut.get(), 10,"hello");
g_temp_test_valid = pOut.get();
return pOut;
}
void testSharedPtr()
{
{
auto ret = getMem();
printf("before [%s]\r\n", g_temp_test_valid);
}
try
{
printf("after [%s]\r\n", g_temp_test_valid);
printf("exits");
}
catch (std::exception & e)
{
printf("%s", e.what());
printf("exception\r\n");
}
}
int main()
{
testSharedPtr();
return 0;
}
ida:
smart_ptr_源码,看接口,有个基类
我们想看其成员的话,里面额外的代码太多了,最方便的是vs2019 自带的watch 本地变量:
吓死个人
不过根据ida 的反汇编,看得出来它就是两个变量,只是由于vs2019 调试能力太强了,导致啥玩意都看出来了,参见如下代码:
其中:
// STRUCT TEMPLATE remove_extent
template <class _Ty>
struct remove_extent { // remove array extent
using type = _Ty;
};
template <class _Ty, size_t _Ix>
struct remove_extent<_Ty[_Ix]> {
using type = _Ty;
};
template <class _Ty>
struct remove_extent<_Ty[]> {
using type = _Ty;
};
template <class _Ty>
using remove_extent_t = typename remove_extent<_Ty>::type;
上面模板类的函数,就是为了,当传入的是数组的时候,取元素类型:
下面这个引用计数的结构,是智能指针的核心结构了,倒是不着急了解它的细节, 先看看实际代码中,它的初始化是怎么样的
// CLASS _Ref_count_base
class __declspec(novtable) _Ref_count_base { // common code for reference counting
private:
#ifdef _M_CEE_PURE
// permanent workaround to avoid mentioning _purecall in msvcurt.lib, ptrustu.lib, or other support libs
virtual void _Destroy() noexcept {
_STD terminate();
}
virtual void _Delete_this() noexcept {
_STD terminate();
}
#else // ^^^ _M_CEE_PURE / !_M_CEE_PURE vvv
virtual void _Destroy() noexcept = 0; // destroy managed resource
virtual void _Delete_this() noexcept = 0; // destroy self
#endif // _M_CEE_PURE
_Atomic_counter_t _Uses = 1;
_Atomic_counter_t _Weaks = 1;
protected:
constexpr _Ref_count_base() noexcept = default; // non-atomic initializations
public:
_Ref_count_base(const _Ref_count_base&) = delete;
_Ref_count_base& operator=(const _Ref_count_base&) = delete;
virtual ~_Ref_count_base() noexcept {} // TRANSITION, should be non-virtual
bool _Incref_nz() noexcept { // increment use count if not zero, return true if successful
auto& _Volatile_uses = reinterpret_cast<volatile long&>(_Uses);
long _Count = _ISO_VOLATILE_LOAD32(_Volatile_uses);
while (_Count != 0) {
const long _Old_value = _INTRIN_RELAXED(_InterlockedCompareExchange)(&_Volatile_uses, _Count + 1, _Count);
if (_Old_value == _Count) {
return true;
}
_Count = _Old_value;
}
return false;
}
void _Incref() noexcept { // increment use count
_MT_INCR(_Uses);
}
void _Incwref() noexcept { // increment weak reference count
_MT_INCR(_Weaks);
}
void _Decref() noexcept { // decrement use count
if (_MT_DECR(_Uses) == 0) {
_Destroy();
_Decwref();
}
}
void _Decwref() noexcept { // decrement weak reference count
if (_MT_DECR(_Weaks) == 0) {
_Delete_this();
}
}
long _Use_count() const noexcept {
return static_cast<long>(_Uses);
}
virtual void* _Get_deleter(const type_info&) const noexcept {
return nullptr;
}
};
explicit shared_ptr(_Ux* _Px) { // construct shared_ptr object that owns _Px
#if _HAS_IF_CONSTEXPR
if constexpr (is_array_v<_Ty>) {
_Setpd(_Px, default_delete<_Ux[]>{});
} else {
_Temporary_owner<_Ux> _Owner(_Px);
_Set_ptr_rep_and_enable_shared(_Owner._Ptr, new _Ref_count<_Ux>(_Owner._Ptr));
_Owner._Ptr = nullptr;
}
template <class _UxptrOrNullptr, class _Dx>
void _Setpd(const _UxptrOrNullptr _Px, _Dx _Dt) { // take ownership of _Px, deleter _Dt
_Temporary_owner_del<_UxptrOrNullptr, _Dx> _Owner(_Px, _Dt);
_Set_ptr_rep_and_enable_shared(
_Owner._Ptr, new _Ref_count_resource<_UxptrOrNullptr, _Dx>(_Owner._Ptr, _STD move(_Dt)));
_Owner._Call_deleter = false;// 这样写,就不释放了,上面的这些操作如果发生了异常,资源可以正常释放
}
template <class _UxptrOrNullptr, class _Dx>
struct _Temporary_owner_del {
_UxptrOrNullptr _Ptr;
_Dx& _Dt;
bool _Call_deleter = true;
explicit _Temporary_owner_del(const _UxptrOrNullptr _Ptr_, _Dx& _Dt_) noexcept : _Ptr(_Ptr_), _Dt(_Dt_) {}
_Temporary_owner_del(const _Temporary_owner_del&) = delete;
_Temporary_owner_del& operator=(const _Temporary_owner_del&) = delete;
~_Temporary_owner_del() {// 注意,默认,这里是会自动释放所拥有的资源的
if (_Call_deleter) {
_Dt(_Ptr);
}
}
};
接下来开始看申请ref_count_resource 的操作,以及_set_ptr_rep_and_enable_shared实现:
// CLASS TEMPLATE _Ref_count_resource
template <class _Resource, class _Dx>
class _Ref_count_resource : public _Ref_count_base { // handle reference counting for object with deleter
public:
_Ref_count_resource(_Resource _Px, _Dx _Dt)
: _Ref_count_base(), _Mypair(_One_then_variadic_args_t(), _STD move(_Dt), _Px) {}
virtual void* _Get_deleter(const type_info& _Typeid) const noexcept override {
#if _HAS_STATIC_RTTI
if (_Typeid == typeid(_Dx)) {
return const_cast<_Dx*>(_STD addressof(_Mypair._Get_first()));
}
#else // _HAS_STATIC_RTTI
(void) _Typeid;
#endif // _HAS_STATIC_RTTI
return nullptr;
}
private:
virtual void _Destroy() noexcept override { // destroy managed resource
_Mypair._Get_first()(_Mypair._Myval2);
}
virtual void _Delete_this() noexcept override { // destroy self
delete this;
}
_Compressed_pair<_Dx, _Resource> _Mypair;
};
压缩匹配数据,继承_Resource 类,存储 _Dx 作为其释放器.
// CLASS TEMPLATE _Ref_count_resource
template <class _Resource, class _Dx>
class _Ref_count_resource : public _Ref_count_base { // handle reference counting for object with deleter
public:
_Ref_count_resource(_Resource _Px, _Dx _Dt)
: _Ref_count_base(), _Mypair(_One_then_variadic_args_t(), _STD move(_Dt), _Px) {}
virtual void* _Get_deleter(const type_info& _Typeid) const noexcept override {
#if _HAS_STATIC_RTTI
if (_Typeid == typeid(_Dx)) {
return const_cast<_Dx*>(_STD addressof(_Mypair._Get_first()));
}
#else // _HAS_STATIC_RTTI
(void) _Typeid;
#endif // _HAS_STATIC_RTTI
return nullptr;
}
private:
virtual void _Destroy() noexcept override { // destroy managed resource
_Mypair._Get_first()(_Mypair._Myval2);
}
virtual void _Delete_this() noexcept override { // destroy self
delete this;
}
_Compressed_pair<_Dx, _Resource> _Mypair;
};
其基类为:
// CLASS _Ref_count_base
class __declspec(novtable) _Ref_count_base { // common code for reference counting
private:
#ifdef _M_CEE_PURE
// permanent workaround to avoid mentioning _purecall in msvcurt.lib, ptrustu.lib, or other support libs
virtual void _Destroy() noexcept {
_STD terminate();
}
virtual void _Delete_this() noexcept {
_STD terminate();
}
#else // ^^^ _M_CEE_PURE / !_M_CEE_PURE vvv
virtual void _Destroy() noexcept = 0; // destroy managed resource 删除管理的资源
virtual void _Delete_this() noexcept = 0; // destroy self 删除当前这个引用计数块
#endif // _M_CEE_PURE
_Atomic_counter_t _Uses = 1;
_Atomic_counter_t _Weaks = 1;
protected:
constexpr _Ref_count_base() noexcept = default; // non-atomic initializations
public:
_Ref_count_base(const _Ref_count_base&) = delete;
_Ref_count_base& operator=(const _Ref_count_base&) = delete;
virtual ~_Ref_count_base() noexcept {} // TRANSITION, should be non-virtual
bool _Incref_nz() noexcept { // increment use count if not zero, return true if successful
auto& _Volatile_uses = reinterpret_cast<volatile long&>(_Uses);
long _Count = _ISO_VOLATILE_LOAD32(_Volatile_uses);
while (_Count != 0) {
const long _Old_value = _INTRIN_RELAXED(_InterlockedCompareExchange)(&_Volatile_uses, _Count + 1, _Count);
if (_Old_value == _Count) {
return true;
}
_Count = _Old_value;
}
return false;
}
void _Incref() noexcept { // increment use count
_MT_INCR(_Uses);
}
void _Incwref() noexcept { // increment weak reference count
_MT_INCR(_Weaks);
}
void _Decref() noexcept { // decrement use count
if (_MT_DECR(_Uses) == 0) {// 管理的资源的引用计数为0 的时候,释放该资源
_Destroy();
_Decwref();
}
}
void _Decwref() noexcept { // decrement weak reference count
if (_MT_DECR(_Weaks) == 0) {// 如果有人有这个块的wreak 引用,当弱引用清空到0 的时候,才delete this,也就是清空自身,不然,别人引用自己的时候,会导致非法访问
_Delete_this();
}
}
long _Use_count() const noexcept {
return static_cast<long>(_Uses);
}
virtual void* _Get_deleter(const type_info&) const noexcept {
return nullptr;
}
};
这个就是刚才的,设置smart_ptr的操作
void _Set_ptr_rep_and_enable_shared(_Ux* const _Px, _Ref_count_base* const _Rx) noexcept { // take ownership of _Px
this->_Ptr = _Px;
this->_Rep = _Rx;
#if _HAS_IF_CONSTEXPR
if constexpr (conjunction_v<negation<is_array<_Ty>>, negation<is_volatile<_Ux>>, _Can_enable_shared<_Ux>>) {
if (_Px && _Px->_Wptr.expired()) {
_Px->_Wptr = shared_ptr<remove_cv_t<_Ux>>(*this, const_cast<remove_cv_t<_Ux>*>(_Px));
}
}
#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv
_Enable_shared_from_this1(*this, _Px,
bool_constant<
conjunction_v<negation<is_array<_Ty>>, negation<is_volatile<_Ux>>, _Can_enable_shared<_Ux>>>{});
#endif // _HAS_IF_CONSTEXPR
}
这个时候,再次贴上我们从vs 搞来的贴图:
明日再战