C++智能指针weak_ptr详解

一、背景

weak_ptr这个指针是在C++11的时候引入的标准库,它的出现完全是为了弥补shared_ptr天生有缺陷的问题,其实相比于上一代的智能指针auto_ptr来说,shared_ptr可以说近乎完美,但由于是通过引用计数实现的它,虽然解决了指针独占的问题,但也引来了引用成环的问题,这种问题靠它自己是没办法解决的,所以在C++11的时候将shared_ptrweak_ptr一起引入了标准库,用来解决循环引用的问题。

二、使用方法

std::weak_ptr 是一种智能指针,它对被 std::shared_ptr 管理的对象存在非拥有性(“弱”)引用。在访问所引用的对象前必须先转换为 std::shared_ptr

std::weak_ptr 用来表达临时所有权的概念:当某个对象只有存在时才需要被访问,而且随时可能被他人删除时,可以使用 std::weak_ptr 来跟踪该对象。需要获得临时所有权时,则将其转换为 std::shared_ptr,此时如果原来的 std::shared_ptr 被销毁,则该对象的生命期将被延长至这个临时的 std::shared_ptr 同样被销毁为止。

三、实例

1.循环引用的例子

class BB;
class AA
{
public:
	AA() { cout << "AA::AA() called" << endl; }
	~AA() { cout << "AA::~AA() called" << endl; }
	shared_ptr<BB> m_bb_ptr;  //!
};

class BB
{
public:
	BB() { cout << "BB::BB() called" << endl; }
	~BB() { cout << "BB::~BB() called" << endl; }
	shared_ptr<AA> m_aa_ptr; //!
};
int main()
{

	shared_ptr<AA> ptr_a(new AA);
	shared_ptr<BB> ptr_b(new BB);
	cout << "ptr_a use_count: " << ptr_a.use_count() << endl;
	cout << "ptr_b use_count: " << ptr_b.use_count() << endl;
	//下面两句导致了AA与BB的循环引用,结果就是AA和BB对象都不会析构
	ptr_a->m_bb_ptr = ptr_b;
	ptr_b->m_aa_ptr = ptr_a;
	cout << "ptr_a use_count: " << ptr_a.use_count() << endl;
	cout << "ptr_b use_count: " << ptr_b.use_count() << endl;
        return 0;
}
	

结果

可以看到由于AA和BB内部的shared_ptr各自保存了对方的一次引用,所以导致了ptr_a和ptr_b销毁的时候都认为内部保存的指针计数没有变成0,所以AA和BB的析构函数不会被调用。解决方法就是把一个shared_ptr替换成weak_ptr。

class BB;
class AA
{
public:
	AA() { cout << "AA::AA() called" << endl; }
	~AA() { cout << "AA::~AA() called" << endl; }
	weak_ptr<BB> m_bb_ptr;  //!
};

class BB
{
public:
	BB() { cout << "BB::BB() called" << endl; }
	~BB() { cout << "BB::~BB() called" << endl; }
	shared_ptr<AA> m_aa_ptr; //!
};

运行结果: 

2.通过锁来保证指针的有效性的例子


std::weak_ptr<int> gw;

void f()
{
	if (auto spt = gw.lock()) { // 使用之前必须复制到 shared_ptr
		std::cout << *spt << "\n";
	}
	else {
		std::cout << "gw is expired\n";
	}
}
int main()
{
	{
		auto sp = std::make_shared<int>(42);
		gw = sp;

		f();
	}

	f();
        return 0;
}

四、总结

  1. weak_ptr虽然是一个模板类,但是不能用来直接定义指向原始指针的对象。
  2. weak_ptr接受shared_ptr类型的变量赋值,但是反过来是行不通的,需要使用lock函数。
  3. weak_ptr设计之初就是为了服务于shared_ptr的,所以不增加引用计数就是它的核心功能。
  4. 由于不知道什么之后weak_ptr所指向的对象就会被析构掉,所以使用之前请先使用expired函数检测一下。

参考:

https://blog.csdn.net/albertsh/article/details/82286999

https://blog.csdn.net/c_base_jin/article/details/79440999?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.compare&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.compare

https://blog.csdn.net/Xiao_CangTian/article/details/89764858?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-9.compare&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-9.compare#1.%20%E5%87%A0%E7%A7%8D%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88

猜你喜欢

转载自blog.csdn.net/sinat_31608641/article/details/107702175