• 2.7. 弱指针

    2.7. 弱指针

    到目前为止介绍的各种智能指针都能在不同的场合下独立使用。 相反,弱指针只有在配合共享指针一起使用时才有意义。 弱指针 boost::weak_ptr 的定义在 boost/weak_ptr.hpp 里。

    1. #include <windows.h>
    2. #include <boost/shared_ptr.hpp>
    3. #include <boost/weak_ptr.hpp>
    4. #include <iostream>
    5.  
    6. DWORD WINAPI reset(LPVOID p)
    7. {
    8. boost::shared_ptr<int> *sh = static_cast<boost::shared_ptr<int>*>(p);
    9. sh->reset();
    10. return 0;
    11. }
    12.  
    13. DWORD WINAPI print(LPVOID p)
    14. {
    15. boost::weak_ptr<int> *w = static_cast<boost::weak_ptr<int>*>(p);
    16. boost::shared_ptr<int> sh = w->lock();
    17. if (sh)
    18. std::cout << *sh << std::endl;
    19. return 0;
    20. }
    21.  
    22. int main()
    23. {
    24. boost::shared_ptr<int> sh(new int(99));
    25. boost::weak_ptr<int> w(sh);
    26. HANDLE threads[2];
    27. threads[0] = CreateThread(0, 0, reset, &sh, 0, 0);
    28. threads[1] = CreateThread(0, 0, print, &w, 0, 0);
    29. WaitForMultipleObjects(2, threads, TRUE, INFINITE);
    30. }
    • 下载源代码

    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() 函数就可以安全的访问对象了。 这就保证了——即使另一个线程要释放对象——由于我们有返回的共享指针,对象依然存在。