C++1 只能指针enable_shared_from_this

智能指针简介

智能指针主要解决动态内存释放问题,采用方式为引入一个计数器;即智能指针中实际有两个指针,故智能指针在内存中的大小时8个字节

  • 一个指向资源对象本身(element_type* _Ptr{nullptr});
  • 一个指向资源对象的引用计数(_Ref_count_base* _Rep{nullptr});该指针中包括连个成员变量_Uses,_Weaks
    • _Uses记录了资源的引用计数,也就是引用资源的shared_ptr 的个数;
    • _Weaks记录了weak_ptr的个数,相当于资源观察者的个数。

enable_shared_from_this引入

当类A被share_ptr管理时,类A的成员函数需要把当前对象作为参数传其他函数时,需要传递一个自身的share_ptr

class A
{
public:
	A() :data(new int)
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
		delete data;
		data = nullptr;
	}
private:
	int* data;
};
int main()
{
	A* p = new A(); // 裸指针指向堆上的对象

	shared_ptr<A> ptr1(p);// 用shared_ptr智能指针管理指针p指向的对象
	shared_ptr<A> ptr2(p);// 用shared_ptr智能指针管理指针p指向的对象
	// 下面两次打印都是1,因此同一个new A()被析构两次,逻辑错误
	cout << ptr1.use_count() << endl;
	cout << ptr2.use_count() << endl;

	return 0;
}

 

class A
{
public:
	A() :data(new int)
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
		delete data;
		data = nullptr;
	}
	shared_ptr<A> getdate()
	{
		return shared_ptr<A>(this);
	}
private:
	int* data;
};
int main()
{
	A* p = new A(); 

	shared_ptr<A> ptr1(p);
	shared_ptr<A> ptr2 = ptr1->getdate();
	cout << ptr1.use_count() << endl;
	cout << ptr2.use_count() << endl;

	return 0;
}

           

上边两种代码的结果是一样的,虽然使用两个智能指针,但是他们的引用次数都为1(如下图所示),都是调用的类A的构造函数,且会释放两次,所以会导致程序崩溃;

若使用拷贝构造函数就不会出现释放两次的现象

shared_ptr<int> ptr1(new int);
shared_ptr<int> ptr2(ptr1);
cout<<ptr1.use_count()<<endl;
cout<<ptr2.use_count()<<endl;

 在类中返回该类对象时,可以使用enable_shared_from_this类的shared_from_this()方法,

class A : public enable_shared_from_this<A>
{
public:
	A() :data(new int)
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
		delete data;
		data = nullptr;
	}
	shared_ptr<A> getdate()
	{
		return shared_from_this();
	}
private:
	int* data;
};

下面时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<_Ty>(_Wptr);
    }

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

......

private:

    mutable weak_ptr<_Ty> _Wptr;
};

 当类A继承enable_shared_from_this后面会有一个成员变量_Wptr,当调用普通构造函数时,会有一个弱智能指针,当调用shared_from_this时,会将_Wptr这个弱智能指针类型转为强智能指针;

    template <class _Ty2, enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
    explicit shared_ptr(const weak_ptr<_Ty2>& _Other) { // construct shared_ptr object that owns resource *_Other
        if (!this->_Construct_from_weak(_Other)) {
            _Throw_bad_weak_ptr();
        }
    }

    template <class _Ty2>
    bool _Construct_from_weak(const weak_ptr<_Ty2>& _Other) noexcept {
        // implement shared_ptr's ctor from weak_ptr, and weak_ptr::lock()
        // if通过判断资源的引用计数是否还在,判定对象的存活状态,对象存活,提升成功;
        if (_Other._Rep && _Other._Rep->_Incref_nz()) {
            _Ptr = _Other._Ptr;
            _Rep = _Other._Rep;
            return true;
        }

        return false;
    }

上述过程没有调用类A的构造函数,没有产生额外的引用计数对象,所以不会存在多次释放; 通过weak_ptr到shared_ptr的提升,还可以在多线程环境中判断对象是否存活或者已经析构释放,在多线程环境中是很安全的

总结

  1. shared_ptr 会增加资源的引用计数,常用于管理对象的生命周期。

  2. weak_ptr 不会增加资源的引用计数,常作为观察者用来判断对象是否存活。

  3. 使用 shared_ptr 的普通拷贝构造函数会产生额外的引用计数对象,可能导致对象多次析构。使用 shared_ptr 的拷贝构造函数则只影响同一资源的同一引用计数的增减。

  4. 当需要返回指向当前对象的 shared_ptr 时,优先使用 enable_shared_from_this 机制。

详细讲解:https://blog.csdn.net/QIANGWEIYUAN/article/details/88973735?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.control

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值