C++ Boost weak_ptr智能指针超详细讲解
作者:无水先生
一、提要
在 C++11 中,boost::weak_ptr是另一类智能指针,一般是用COM组件生成、调用,本文阐述这种指针的特点和用法。
二、特别智能指针(Special Smart Pointers)
到目前为止介绍的每个智能指针都可以在不同的场景中单独使用。但是,boost::weak_ptr 仅在与 boost::shared_ptr 结合使用时才有意义。 boost::weak_ptr 在 boost/weak_ptr.hpp 中定义。
示例1.Usingboost::weak_ptr
#include <boost/shared_ptr.hpp> #include <boost/weak_ptr.hpp> #include <thread> #include <functional> #include <iostream> void reset(boost::shared_ptr<int> &sh) { sh.reset(); } void print(boost::weak_ptr<int> &w) { boost::shared_ptr<int> sh = w.lock(); if (sh) std::cout << *sh << '\n'; } int main() { boost::shared_ptr<int> sh{new int{99}}; boost::weak_ptr<int> w{sh}; std::thread t1{reset, std::ref(sh)}; std::thread t2{print, std::ref(w)}; t1.join(); t2.join(); }
boost::weak_ptr 必须使用 boost::shared_ptr 进行初始化。它最重要的成员函数是 lock()。 lock() 返回一个 boost::shared_ptr ,它与用于初始化弱指针的共享指针共享所有权。如果共享指针为空,则返回的指针也将为空。
boost::weak_ptr 是有意义的,只要一个函数需要与一个由共享指针管理的对象一起工作,但对象的生命周期不依赖于函数本身。该函数只能使用该对象,只要它由程序中其他位置的至少一个共享指针拥有。如果共享指针被重置,则对象无法保持活动状态,因为相应函数内有一个额外的共享指针。
示例 1 在 main() 中创建了两个线程。第一个线程执行函数 reset(),该函数接收对共享指针的引用。第二个线程执行函数 print(),该函数接收对弱指针的引用。这个弱指针之前已经用共享指针初始化了。
程序启动后,reset() 和 print() 会同时执行。但是,无法预测执行顺序。这会导致当对象被 print() 访问时,reset() 会破坏该对象的潜在问题。
弱指针通过以下方式解决了这个问题:调用 lock() 返回一个共享指针,该指针指向一个有效对象(如果在调用时存在一个有效对象)。如果不是,则共享指针设置为 0,相当于一个空指针。
boost::weak_ptr 本身对对象的生命周期没有任何影响。为了安全地访问 print() 函数中的对象,lock() 返回一个 boost::shared_ptr。这保证了即使不同的线程尝试释放对象,由于返回的共享指针,它仍将继续存在。
示例2 .使用boost::intrusive_ptr
#include <boost/intrusive_ptr.hpp> #include <atlbase.h> #include <iostream> void intrusive_ptr_add_ref(IDispatch *p) { p->AddRef(); } void intrusive_ptr_release(IDispatch *p) { p->Release(); } void check_windows_folder() { CLSID clsid; CLSIDFromProgID(CComBSTR{"Scripting.FileSystemObject"}, &clsid); void *p; CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, __uuidof(IDispatch), &p); boost::intrusive_ptr<IDispatch> disp{static_cast<IDispatch*>(p), false}; CComDispatchDriver dd{disp.get()}; CComVariant arg{"C:\\Windows"}; CComVariant ret{false}; dd.Invoke1(CComBSTR{"FolderExists"}, &arg, &ret); std::cout << std::boolalpha << (ret.boolVal != 0) << '\n'; } int main() { CoInitialize(0); check_windows_folder(); CoUninitialize(); }
通常,boost::intrusive_ptr 的工作方式与 boost::shared_ptr 相同。但是,虽然 boost::shared_ptr 会跟踪引用特定对象的共享指针的数量,但开发人员在使用 boost::intrusive_ptr 时必须这样做。如果其他类已经跟踪引用,这可能是有意义的。
boost::intrusive_ptr 在 boost/intrusive_ptr.hpp 中定义。
示例 2 使用 COM 提供的功能,因此只能在 Windows 上构建和运行。 COM 对象是 boost::intrusive_ptr 的一个很好的例子,因为它们跟踪引用它们的指针的数量。内部引用计数器可以通过成员函数 AddRef() 和 Release() 递增或递减 1。一旦计数器达到 0,COM 对象就会自动销毁。
从 intrusive_ptr_add_ref() 和 intrusive_ptr_release() 调用两个成员函数 AddRef() 和 Release()。 Boost.Intrusive 希望开发人员定义这两个函数,当引用计数器必须递增或递减时,它们会自动调用。传递给这些函数的参数是指向用于实例化类模板 boost::intrusive_ptr 的类型的指针。
此示例中使用的 COM 对象称为 FileSystemObject,默认情况下可在 Windows 上使用。它提供对底层文件系统的访问,例如,检查给定目录是否存在。在示例 1.9 中,检查了名为 C:\Windows 的目录是否存在。其内部工作方式仅取决于 COM,与 boost::intrusive_ptr 的功能无关。关键是一旦侵入指针 disp 在 check_windows_folder() 结束时超出范围,函数 intrusive_ptr_release() 就会被自动调用。这反过来会将 FileSystemObject 的内部引用计数器减为 0 并销毁该对象。
传递给 boost::intrusive_ptr 的构造函数的参数 false 会阻止 intrusive_ptr_add_ref() 被调用。当使用 CoCreateInstance() 创建 COM 对象时,计数器已设置为 1。因此,不得使用 intrusive_ptr_add_ref() 递增。
到此这篇关于C++ Boost weak_ptr智能指针超详细讲解的文章就介绍到这了,更多相关C++ Boost weak_ptr内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!