智能指针解读(2)

本文详细介绍了C++中的四种智能指针(auto_ptr,unique_ptr,shared_ptr,weak_ptr),探讨了它们的工作原理,如auto_ptr的自动清理机制,unique_ptr的移动特性,以及shared_ptr的引用计数和避免交叉引用的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前面一篇文章,我讲解了智能指针的原理,并实现了一个简单的智能指针。为了加深对智能指针的理解,在这篇文章中,我把C++中的几个智能指针讲解下:auto_ptr, unique_ptr, shared_ptr, weak_ptr。

1、auto_ptr

前面的文章我们把smart_ptr的拷贝构造函数、赋值运算符都禁掉了。auto_ptr在拷贝构造函数和赋值运算符里是怎么处理的呢?它会把原来的指针赋为nullptr。

template<class T>
class auto_ptr {
public:
	auto_ptr(T* _ptr) : ptr(_ptr) {

	}

	auto_ptr(auto_ptr& _ap) : ptr(_ap.ptr) {
		_ap.ptr = nullptr;
	}

	auto_ptr<T>& operator = (auto_ptr<T>& _ap) {
		if (ptr != _ap.ptr) {
			ptr = _ap.ptr;
			_ap.ptr = nullptr;
		}

		return *this;
	}

	~auto_ptr() {
		delete ptr;
		ptr = nullptr;
	}

	T& operator * () {
		return *ptr;
	}

	T* operator -> () {
		return ptr;
	}
private:
	T* ptr;
};

3、unique_ptr

unique_ptr是c++11版本库中提供的智能指针,它直接将拷贝构造函数和赋值重载函数给禁用掉。所以unique_ptr只能move,不能赋值。

4、shared_ptr

shared_ptr允许多个智能指针可以指向同一块资源,并且能够保证共享的资源只会被释放一次。
shared_ptr采用的是引用计数原理来实现多个shared_ptr对象之间共享资源:
(1)引用计数用来记录该资源被几个对象共享。
(2)当一个shared_ptr对象被销毁时(调用析构函数),析构函数内就会将该计数减1。
(3)如果引用计数减为0后,则表示自己是最后一个使用该资源的shared_ptr对象,必须释放资源。
(4)如果引用计数不是0,就说明自己还有其他对象在使用,则不能释放该资源。

在使用shared_ptr时,要注意不要让2个shared_ptr指向同一个原始指针,比如:

A* p = new A(10);
shared_ptr<A> sp1(p), sp2(p);

sp1 和 sp2 并不会共享同一个对 p 的引用计数,而是各自将对 p 的引用计数都记为 1(sp2 无法知道 p 已经被 sp1 托管过)。这样,当 sp1 消亡时要析构 p,sp2 消亡时要再次析构 p,这会导致程序崩溃。

5、weak_ptr

weak_ptr类的对象可以指向shared_ptr,但不会改变shared_ptr的引用计数。一旦最后一个shared_ptr被销毁时,对象就会被释放。
weak_ptr并没有重载operator->和operator *操作符,因此不可直接通过weak_ptr使用对象,典型的用法是调用其lock函数来获得shared_ptr示例,进而访问原始对象。

我们来看一个shared_ptr交叉引用的例子:

class B;
class A
{
public:
	shared_ptr<B> sp;

	~A(){
		cout << "~A"<<endl;
	}
};
class B
{
public:
	shared_ptr<A> sp;
	~B(){
		cout << "~B"<<endl;
	}
};

void fun() {
	shared_ptr<B> pb(new B());
	shared_ptr<A> pa(new A());

	pb->sp = pa;
	cout << "pb.use_count " << pb.use_count() << endl;//1
	cout << "pa.use_count " << pa.use_count() << endl;//2

	pa->sp = pb;
	cout << "pb.use_count " << pb.use_count() << endl;//2
	cout << "pa.use_count " << pa.use_count() << endl;//2

    //并没有输出 ~A, ~B,也就是class B;
class A
{
public:
	shared_ptr<B> sp;

	~A(){
		cout << "~A"<<endl;
	}
};
class B
{
public:
	shared_ptr<A> sp;
	~B(){
		cout << "~B"<<endl;
	}
};

void fun() {
	shared_ptr<B> pb(new B());
	shared_ptr<A> pa(new A());

	pb->sp = pa;
	cout << "pb.use_count " << pb.use_count() << endl;//1
	cout << "pa.use_count " << pa.use_count() << endl;//2

	pa->sp = pb;
	cout << "pb.use_count " << pb.use_count() << endl;//2
	cout << "pa.use_count " << pa.use_count() << endl;//2

    //没有输出~A, ~B。也就是没有调用A和B的析构函数。
}

怎么去避免这种交叉引用呢?这就需要使用weak_ptr:把A中的shared_ptr<B> sp改为weak_ptr<B> sp_weak,这样传递时不会增加sp引用计数use_count()的值,所以最终能够使A、B资源正常释放:

class B;
class A
{
public:
	//shared_ptr<B> sp;
	weak_ptr<B> sp_weak;

	~A(){
		cout << "~A"<<endl;
	}
};
class B
{
public:
	shared_ptr<A> sp;
	~B(){
		cout << "~B"<<endl;
	}
};

void fun() {
	shared_ptr<B> pb(new B());
	shared_ptr<A> pa(new A());

	pb->sp = pa;
	cout << "pb.use_count " << pb.use_count() << endl;//1
	cout << "pa.use_count " << pa.use_count() << endl;//2

	//pa->sp = pb;
	pa->sp_weak = pb;
	cout << "pb.use_count " << pb.use_count() << endl;//1
	cout << "pa.use_count " << pa.use_count() << endl;//2

	shared_ptr<B> pa2 = pa->sp_weak.lock();

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值