首页 > 后端开发 > C++ > 正文

C++智能指针比较运算 所有权比较规则

P粉602998670
发布: 2025-09-01 10:29:01
原创
1031人浏览过
<blockquote>智能指针的比较不仅限于地址,std::unique_ptr直接比较指针地址,而std::shared_ptr和std::weak_ptr通过std::owner_less比较是否共享同一控制块,以判断所有权身份,尤其在容器键值、缓存和观察者模式中至关重要。</blockquote> <p><img src="https://img.php.cn/upload/article/000/969/633/175669374140022.png" alt="c++智能指针比较运算 所有权比较规则"></p> <p>在C++智能指针的世界里,比较运算远不止于简单的地址判断。当我们谈及智能指针的“所有权比较规则”时,核心在于理解它们在面对底层资源时,如何界定“相同”或“不同”的管理关系。对于<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::unique_ptr</pre>
登录后复制
</div>,比较通常只涉及其内部裸指针的地址。但对于<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::shared_ptr</pre>
登录后复制
</div>和<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div>,所有权比较则是一个更深层次的概念,它关乎两个指针是否共享同一个控制块(control block),从而共同管理着同一份资源。</p> <p>C++智能指针的比较运算,尤其是涉及所有权的概念,其实是围绕着不同智能指针类型及其设计哲学展开的。</p> <p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::unique_ptr</pre>
登录后复制
</div> 的比较相对直接。由于它独占资源,任何两个非空的<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::unique_ptr</pre>
登录后复制
</div>如果指向同一地址,那通常意味着其中一个已经通过<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::move</pre>
登录后复制
</div>转移了所有权,或者存在逻辑上的错误。因此,<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::unique_ptr</pre>
登录后复制
</div>的<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">==</pre>
登录后复制
</div>、<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">!=</pre>
登录后复制
</div>、<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;"><</pre>
登录后复制
</div>等比较运算符,本质上都是对其内部存储的裸指针进行比较。它们之间没有“共享所有权”的概念,所以也就谈不上所有权层面的比较规则。比如,<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">p1 == p2</pre>
登录后复制
</div> 实际上就是 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">p1.get() == p2.get()</pre>
登录后复制
</div>。</p> <p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::shared_ptr</pre>
登录后复制
</div> 和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div> 的情况则复杂得多,也更有趣。它们引入了“控制块”的概念,这是实现共享所有权和生命周期管理的关键。</p> <p><span>立即学习</span>“<a href="https://pan.quark.cn/s/6e7abc4abb9f" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">C++免费学习笔记(深入)</a>”;</p> <ul> <li><p><strong><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::shared_ptr</pre>
登录后复制
</div> 的默认比较 (<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">==</pre>
登录后复制
</div>, <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">!=</pre>
登录后复制
</div>)</strong>: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::shared_ptr</pre>
登录后复制
</div> 重载的 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">==</pre>
登录后复制
</div> 和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">!=</pre>
登录后复制
</div> 运算符,和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::unique_ptr</pre>
登录后复制
</div> 类似,也是比较它们所持有的裸指针地址。也就是说,<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">sp1 == sp2</pre>
登录后复制
</div> 等价于 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">sp1.get() == sp2.get()</pre>
登录后复制
</div>。这仅仅判断两个智能指针是否指向了内存中的同一个具体对象。这并不能完全反映它们在所有权上的关系。例如,你可能有两个 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">shared_ptr</pre>
登录后复制
</div>,一个指向基类子对象,一个指向派生类对象,它们可能指向同一块内存的起始地址,但它们的类型不同。更重要的是,它们可能通过别名构造函数(aliasing constructor)指向不同的地址,但却共享同一个控制块。</p></li> <li> <p><strong>所有权比较 (<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::owner_less</pre>
登录后复制
</div>)</strong>: 为了真正比较智能指针的“所有权身份”,C++<a style="color:#f60; text-decoration:underline;" title="标准库" href="https://www.php.cn/zt/74427.html" target="_blank">标准库</a>提供了 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::owner_less</pre>
登录后复制
</div> 模板。这是一个函数对象,用于为 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::shared_ptr</pre>
登录后复制
</div> 和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div> 提供严格弱序(strict weak ordering),其核心就是比较它们是否共享同一个控制块。如果两个智能指针共享同一个控制块,那么它们就拥有相同的“所有权身份”,即便它们通过 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">get()</pre>
登录后复制
</div> 返回的裸指针地址可能不同(例如,通过别名构造函数创建的 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">shared_ptr</pre>
登录后复制
</div>)。</p> <p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::owner_less</pre>
登录后复制
</div> 对于在有序容器(如 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::map</pre>
登录后复制
</div> 或 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::set</pre>
登录后复制
</div>)中使用智能指针作为键至关重要。它确保了即便智能指针所指向的裸指针地址不同,只要它们管理的是同一份资源(即共享同一控制块),就会被视为等价。</p> <p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div> 的比较也遵循类似的逻辑。<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div> 的 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">==</pre>
登录后复制
</div> 和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">!=</pre>
登录后复制
</div> 运算符会比较其内部裸指针的地址,并且如果两个 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">weak_ptr</pre>
登录后复制
</div> 都已过期(expi<a style="color:#f60; text-decoration:underline;" title="red" href="https://www.php.cn/zt/122037.html" target="_blank">red</a>),它们也被认为是相等的。而 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::owner_less</pre>
登录后复制
</div> 则允许你比较 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div> 甚至 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::shared_ptr</pre>
登录后复制
</div> 和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div> 之间是否共享同一控制块,这对于判断它们是否“观察”着同一份资源非常有用,即使资源可能已经失效。</p> </li> </ul> <h3> <a style="color:#f60; text-decoration:underline;" title="为什么" href="https://www.php.cn/zt/92702.html" target="_blank">为什么</a> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::shared_ptr</pre>
登录后复制
</div> 的相等比较 (<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">==</pre>
登录后复制
</div>) 和所有权比较 (<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::owner_less</pre>
登录后复制
</div>) 行为不同?</h3> <p>这其实是一个非常关键的细节,也是很多初学者容易混淆的地方。在我看来,这种差异的设计是出于实用性和灵活性两方面的考虑。</p> <p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::shared_ptr</pre>
登录后复制
</div> 的 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">operator==</pre>
登录后复制
</div> 遵循的是大多数指针类型比较的直观语义:它比较的是两个指针所“指向”的内存地址是否相同。这就像你问“这两本书是不是同一本?”你可能只是看它们的封面标题是否一样。在很多场景下,我们确实只需要知道两个 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">shared_ptr</pre>
登录后复制
</div> 是否指向了内存中的同一个对象实例。比如,你可能在遍历一个列表,想看看某个 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">shared_ptr</pre>
登录后复制
</div> 是否已经存在于列表中,此时比较 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">get()</pre>
登录后复制
</div> 返回的地址是最直接、效率也最高的做法。</p> <p>然而,<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::owner_less</pre>
登录后复制
</div> 提供的所有权比较,则更像是问“这两本书是不是由同一个出版商、同一个作者创作的,即便它们的版本或装帧不同?”它关注的是更深层次的“身份”——控制块。一个经典的例子就是 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">shared_ptr</pre>
登录后复制
</div> 的别名构造函数(aliasing constructor)。</p> <div class="aritcle_card"> <a class="aritcle_card_img" href="/ai/2158"> <img src="https://img.php.cn/upload/ai_manual/000/000/000/175680310874179.png" alt="拍我AI"> </a> <div class="aritcle_card_info"> <a href="/ai/2158">拍我AI</a> <p>AI视频生成平台PixVerse的国内版本</p> <div class=""> <img src="/static/images/card_xiazai.png" alt="拍我AI"> <span>353</span> </div> </div> <a href="/ai/2158" class="aritcle_card_btn"> <span>查看详情</span> <img src="/static/images/cardxiayige-3.png" alt="拍我AI"> </a> </div> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:cpp;toolbar:false;'>struct Resource { int id; std::string name; }; struct Member { int value; }; // 假设Resource里有一个Member类型的成员 struct ComplexResource { int resource_id; Member internal_member; }; std::shared_ptr<ComplexResource> res_ptr(new ComplexResource{1, {100}}); // 创建一个shared_ptr,它与res_ptr共享所有权,但指向的是res_ptr管理的对象的某个成员 std::shared_ptr<Member> member_ptr(res_ptr, &res_ptr->internal_member); // 此时: // res_ptr.get() 和 member_ptr.get() 是不同的地址 // res_ptr == member_ptr 会是 false (因为get()不同) // 但是,它们共享同一个控制块,因为member_ptr的生命周期依赖于res_ptr // 所以,std::owner_less()(res_ptr, member_ptr) 会是 false // 而 !(std::owner_less()(res_ptr, member_ptr) || std::owner_less()(member_ptr, res_ptr)) 会是 true // 这表示它们在所有权层面上是等价的。</pre>
登录后复制
</div><p>在这个例子中,<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">res_ptr</pre>
登录后复制
</div> 和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">member_ptr</pre>
登录后复制
</div> 指向的内存地址截然不同,所以 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">==</pre>
登录后复制
</div> 比较会返回 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">false</pre>
登录后复制
</div>。但它们却共享同一个控制块,意味着它们的生命周期是绑定在一起的,当 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">res_ptr</pre>
登录后复制
</div> 的引用计数归零时,<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">ComplexResource</pre>
登录后复制
</div> 对象才会被销毁。<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">member_ptr</pre>
登录后复制
</div> 仅仅是提供了一个指向 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">internal_member</pre>
登录后复制
</div> 的视图,但它本身并不拥有 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">internal_member</pre>
登录后复制
</div> 的独立生命周期。</p> <p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::owner_less</pre>
登录后复制
</div> 的存在,正是为了解决这种“指向不同,但管理同一份资源”的场景。它允许你在需要根据资源管理身份来区分对象时,能够有一个可靠的机制。这在将 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">shared_ptr</pre>
登录后复制
</div> 或 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">weak_ptr</pre>
登录后复制
</div> 作为键存储在 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::map</pre>
登录后复制
</div> 或 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::set</pre>
登录后复制
</div> 这样的有序关联容器中时尤为重要,因为这些容器需要一个稳定的、能提供严格弱序的比较器来正确地插入和查找元素。如果只用 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">operator==</pre>
登录后复制
</div> 来判断,上面的 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">res_ptr</pre>
登录后复制
</div> 和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">member_ptr</pre>
登录后复制
</div> 就会被认为是两个不同的键,即便它们在逻辑上是关联到同一份核心资源的。</p> <h3><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div> 如何参与所有权比较,它与 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::shared_ptr</pre>
登录后复制
</div> 有何异同?</h3> <p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div> 在所有权比较中扮演的角色,我觉得用“观察者”来形容最为贴切。它本身不拥有资源,只是对 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::shared_ptr</pre>
登录后复制
</div> 所管理资源的一个“弱引用”。这意味着 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div> 不会增加资源的引用计数,因此它的存在不会阻止资源被销毁。</p> <p>在比较行为上,<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div> 和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::shared_ptr</pre>
登录后复制
</div> 有着相似之处,也有其独特之处:</p> <ol> <li><p><strong>裸指针比较 (<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">==</pre>
登录后复制
</div>, <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">!=</pre>
登录后复制
</div>)</strong>: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div> 同样重载了 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">==</pre>
登录后复制
</div> 和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">!=</pre>
登录后复制
</div> 运算符,它们也是比较内部存储的裸指针地址。不过这里有个小细节:如果两个 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">weak_ptr</pre>
登录后复制
</div> 都已经过期(即它们所观察的 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">shared_ptr</pre>
登录后复制
</div> 已经销毁了资源),那么它们也会被认为是相等的,因为它们都指向了无效的地址(通常是 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">nullptr</pre>
登录后复制
</div>)。这与 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">shared_ptr</pre>
登录后复制
</div> 略有不同,<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">shared_ptr</pre>
登录后复制
</div> 只有在 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">get()</pre>
登录后复制
</div> 返回相同地址时才相等。</p></li> <li> <p><strong>所有权比较 (<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::owner_less</pre>
登录后复制
</div>)</strong>: 这才是 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div> 在所有权比较中最有价值的地方。<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::owner_less</pre>
登录后复制
</div> 不仅可以比较两个 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">shared_ptr</pre>
登录后复制
</div>,两个 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">weak_ptr</pre>
登录后复制
</div>,甚至可以比较一个 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">shared_ptr</pre>
登录后复制
</div> 和一个 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">weak_ptr</pre>
登录后复制
</div>,来判断它们是否指向同一个控制块。</p> <p>想象这样一个场景:你有一个缓存系统,里面存储了资源的 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div>。当需要访问某个资源时,你会尝试 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">lock()</pre>
登录后复制
</div> 这个 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">weak_ptr</pre>
登录后复制
</div> 获得一个 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">shared_ptr</pre>
登录后复制
</div>。但在某些情况下,你可能需要判断当前正在使用的 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">shared_ptr</pre>
登录后复制
</div> 是否与缓存中的某个 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">weak_ptr</pre>
登录后复制
</div> 观察的是同一个资源,即使缓存中的 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">weak_ptr</pre>
登录后复制
</div> 可能已经过期了。</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:cpp;toolbar:false;'>std::shared_ptr<int> sp1(new int(10)); std::weak_ptr<int> wp1 = sp1; std::shared_ptr<int> sp2(new int(20)); std::weak_ptr<int> wp2 = sp2; // sp1 和 wp1 共享同一个控制块 bool same_owner_sp1_wp1 = !(std::owner_less<std::shared_ptr<int>>()(sp1, wp1) || std::owner_less<std::shared_ptr<int>>()(wp1, sp1)); // true // sp1 和 wp2 不共享同一个控制块 bool same_owner_sp1_wp2 = !(std::owner_less<std::shared_ptr<int>>()(sp1, wp2) || std::owner_less<std::shared_ptr<int>>()(wp2, sp1)); // false // 让 sp1 过期,观察资源被销毁 sp1.reset(); // 此时 wp1 已经过期,但它仍然知道自己曾经观察的是哪个控制块 // 它可以和另一个 shared_ptr 进行所有权比较,看它们是否“曾经”指向同一个资源 std::shared_ptr<int> sp_new(new int(30)); bool same_owner_wp1_sp_new = !(std::owner_less<std::shared_ptr<int>>()(wp1, sp_new) || std::owner_less<std::shared_ptr<int>>()(sp_new, wp1)); // false</pre>
登录后复制
</div><p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div> 能够通过 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::owner_less</pre>
登录后复制
</div> 参与所有权比较,这使得它在构建复杂的对象生命周期管理和缓存机制时非常强大。它允许我们在不影响资源生命周期的情况下,跟踪并识别资源的“身份”。</p> </li> </ol> <h3>在实际开发中,何时以及如何正确使用智能指针的所有权比较?</h3> <p>在实际的C++开发中,正确理解并运用智能指针的所有权比较,能够帮助我们编写出更健壮、更高效的代码,尤其是在处理资源管理和对象生命周期时。</p> <p><strong>何时使用:</strong></p> <ol> <li> <p><strong>作为关联容器的键 (Key in Associative Cont<a style="color:#f60; text-decoration:underline;" title="ai" href="https://www.php.cn/zt/17539.html" target="_blank">ai</a>ners)</strong>: 这是 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::owner_less</pre>
登录后复制
</div> 最常见且最重要的应用场景。如果你需要将 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::shared_ptr</pre>
登录后复制
</div> 或 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div> 对象作为 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::map</pre>
登录后复制
</div> 或 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::set</pre>
登录后复制
</div> 的键,并且你希望这些容器能够根据智能指针所管理的“同一份资源”来唯一识别键,而不是仅仅根据裸指针地址,那么你就必须使用 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::owner_less</pre>
登录后复制
</div> 作为自定义比较器。</p> <ul> <li> <strong>示例场景</strong>:一个<a style="color:#f60; text-decoration:underline;" title="资源管理器" href="https://www.php.cn/zt/19011.html" target="_blank">资源管理器</a>,需要根据资源的唯一“身份”来存储和查找其元数据。</li> <li> <strong>错误做法</strong>:直接使用 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::map<std::shared_ptr<MyResource>, MyMetadata></pre>
登录后复制
</div>,这会默认使用 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::shared_ptr</pre>
登录后复制
</div> 的 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">operator<</pre>
登录后复制
</div>,而这个运算符在C++17之前是基于裸指针地址的,C++17之后才被定义为基于 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">owner_less</pre>
登录后复制
</div>。为了兼容性和明确性,最好还是显式指定。</li> </ul> </li> <li><p><strong>实现缓存机制 (Caching Mechanisms)</strong>: 在缓存系统中,你可能希望存储 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::weak_ptr</pre>
登录后复制
</div> 来避免持有资源导致其无法销毁,同时又需要能够快速判断一个新来的 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">shared_ptr</pre>
登录后复制
</div> 是否与缓存中某个 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">weak_ptr</pre>
登录后复制
</div> 指向同一份(或曾经指向同一份)资源。<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::owner_less</pre>
登录后复制
</div> 就能帮你完成这个任务。</p></li> <li><p><strong>调试与日志 (Debugging and Logging)</strong>: 当你在调试复杂的对象图或资源依赖关系时,可能需要验证两个不同的 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">shared_ptr</pre>
登录后复制
</div> 或 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">weak_ptr</pre>
登录后复制
</div> 是否确实管理着同一个底层对象。<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::owner_less</pre>
登录后复制
</div> 提供了一个明确的语义来检查这种“所有权身份”的等价性。</p></li> <li><p><strong>Observer 模式或事件系统 (Observer Pattern/Event Systems)</strong>: 在一些Observer模式的实现中,Subject可能持有对Observer的 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">weak_ptr</pre>
登录后复制
</div>。当Subject需要通知Observer时,它会尝试 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">lock()</pre>
登录后复制
</div> 这些 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">weak_ptr</pre>
登录后复制
</div>。如果系统中需要根据Observer的“身份”来注册或取消注册,<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::owner_less</pre>
登录后复制
</div> 可以帮助你识别同一Observer的不同 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">weak_ptr</pre>
登录后复制
</div> 实例。</p></li> </ol> <p><strong>如何正确使用:</strong></p> <ol><li> <strong>对于 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">std::unique_ptr</pre>
登录后复制
</div></strong>: 坚持使用 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">==</pre>
登录后复制
</div> 和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">!=</pre>
登录后复制
</div> 运算符来比较它们所管理的裸指针地址。因为 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">unique_ptr</pre>
登录后复制
</div> 没有共享所有权的概念,其比较语义就是如此。<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'></pre>
登录后复制
</div></li></ol>

以上就是C++智能指针比较运算 所有权比较规则的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号