2.7. 弱指针
到目前为止介绍的各种智能指针都能在不同的场合下独立使用。 相反,弱指针只有在配合共享指针一起使用时才有意义。 弱指针 boost::weak_ptr
的定义在 boost/weak_ptr.hpp
里。
- #include <windows.h>
- #include <boost/shared_ptr.hpp>
- #include <boost/weak_ptr.hpp>
- #include <iostream>
- DWORD WINAPI reset(LPVOID p)
- {
- boost::shared_ptr<int> *sh = static_cast<boost::shared_ptr<int>*>(p);
- sh->reset();
- return 0;
- }
- DWORD WINAPI print(LPVOID p)
- {
- boost::weak_ptr<int> *w = static_cast<boost::weak_ptr<int>*>(p);
- boost::shared_ptr<int> sh = w->lock();
- if (sh)
- std::cout << *sh << std::endl;
- return 0;
- }
- int main()
- {
- boost::shared_ptr<int> sh(new int(99));
- boost::weak_ptr<int> w(sh);
- HANDLE threads[2];
- threads[0] = CreateThread(0, 0, reset, &sh, 0, 0);
- threads[1] = CreateThread(0, 0, print, &w, 0, 0);
- WaitForMultipleObjects(2, threads, TRUE, INFINITE);
- }
boost::weak_ptr
必定总是通过 boost::shared_ptr
来初始化的。一旦初始化之后,它基本上只提供一个有用的方法: lock()
。此方法返回的boost::shared_ptr
与用来初始化弱指针的共享指针共享所有权。 如果这个共享指针不含有任何对象,返回的共享指针也将是空的。
当函数需要一个由共享指针所管理的对象,而这个对象的生存期又不依赖于这个函数时,就可以使用弱指针。 只要程序中还有一个共享指针掌管着这个对象,函数就可以使用该对象。 如果共享指针复位了,就算函数里能得到一个共享指针,对象也不存在了。
上例的 main()
函数中,通过 Windows API 创建了2个线程。 于是乎,该例只能在 Windows 平台上编译运行。
第一个线程函数 reset()
的参数是一个共享指针的地址。 第二个线程函数 print()
的参数是一个弱指针的地址。 这个弱指针是之前通过共享指针初始化的。
一旦程序启动之后,reset()
和 print()
就都开始执行了。 不过执行顺序是不确定的。 这就导致了一个潜在的问题:reset()
线程在销毁对象的时候print()
线程可能正在访问它。
通过调用弱指针的 lock()
函数可以解决这个问题:如果对象存在,那么 lock()
函数返回的共享指针指向这个合法的对象。否则,返回的共享指针被设置为0,这等价于标准的null指针。
弱指针本身对于对象的生存期没有任何影响。 lock()
返回一个共享指针,print()
函数就可以安全的访问对象了。 这就保证了——即使另一个线程要释放对象——由于我们有返回的共享指针,对象依然存在。