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

智能指针的比较不仅限于地址,std::unique_ptr直接比较指针地址,而std::shared_ptr和std::weak_ptr通过std::owner_less比较是否共享同一控制块,以判断所有权身份,尤其在容器键值、缓存和观察者模式中至关重要。

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

在C++智能指针的世界里,比较运算远不止于简单的地址判断。当我们谈及智能指针的“所有权比较规则”时,核心在于理解它们在面对底层资源时,如何界定“相同”或“不同”的管理关系。对于

std::unique_ptr

,比较通常只涉及其内部裸指针的地址。但对于

std::shared_ptr

std::weak_ptr

,所有权比较则是一个更深层次的概念,它关乎两个指针是否共享同一个控制块(control block),从而共同管理着同一份资源。

C++智能指针的比较运算,尤其是涉及所有权的概念,其实是围绕着不同智能指针类型及其设计哲学展开的。

std::unique_ptr

的比较相对直接。由于它独占资源,任何两个非空的

std::unique_ptr

如果指向同一地址,那通常意味着其中一个已经通过

std::move

转移了所有权,或者存在逻辑上的错误。因此,

std::unique_ptr

==

!=

<

等比较运算符,本质上都是对其内部存储的裸指针进行比较。它们之间没有“共享所有权”的概念,所以也就谈不上所有权层面的比较规则。比如,

p1 == p2

实际上就是

p1.get() == p2.get()

std::shared_ptr

std::weak_ptr

的情况则复杂得多,也更有趣。它们引入了“控制块”的概念,这是实现共享所有权和生命周期管理的关键。

立即学习C++免费学习笔记(深入)”;

  • std::shared_ptr

    的默认比较 (

    ==

    ,

    !=

    )

    std::shared_ptr

    重载的

    ==

    !=

    运算符,和

    std::unique_ptr

    类似,也是比较它们所持有的裸指针地址。也就是说,

    sp1 == sp2

    等价于

    sp1.get() == sp2.get()

    。这仅仅判断两个智能指针是否指向了内存中的同一个具体对象。这并不能完全反映它们在所有权上的关系。例如,你可能有两个

    shared_ptr

    ,一个指向基类子对象,一个指向派生类对象,它们可能指向同一块内存的起始地址,但它们的类型不同。更重要的是,它们可能通过别名构造函数(aliasing constructor)指向不同的地址,但却共享同一个控制块。

  • 所有权比较 (

    std::owner_less

    ):为了真正比较智能指针的“所有权身份”,C++标准库提供了

    std::owner_less

    模板。这是一个函数对象,用于为

    std::shared_ptr

    std::weak_ptr

    提供严格弱序(strict weak ordering),其核心就是比较它们是否共享同一个控制块。如果两个智能指针共享同一个控制块,那么它们就拥有相同的“所有权身份”,即便它们通过

    get()

    返回的裸指针地址可能不同(例如,通过别名构造函数创建的

    shared_ptr

    )。

    std::owner_less

    对于在有序容器(如

    std::map

    std::set

    )中使用智能指针作为键至关重要。它确保了即便智能指针所指向的裸指针地址不同,只要它们管理的是同一份资源(即共享同一控制块),就会被视为等价。

    std::weak_ptr

    的比较也遵循类似的逻辑。

    std::weak_ptr

    ==

    !=

    运算符会比较其内部裸指针的地址,并且如果两个

    weak_ptr

    都已过期(expired),它们也被认为是相等的。而

    std::owner_less

    则允许你比较

    std::weak_ptr

    甚至

    std::shared_ptr

    std::weak_ptr

    之间是否共享同一控制块,这对于判断它们是否“观察”着同一份资源非常有用,即使资源可能已经失效。

为什么

std::shared_ptr

的相等比较 (

==

) 和所有权比较 (

std::owner_less

) 行为不同?

这其实是一个非常关键的细节,也是很多初学者容易混淆的地方。在我看来,这种差异的设计是出于实用性和灵活性两方面的考虑。

std::shared_ptr

operator==

遵循的是大多数指针类型比较的直观语义:它比较的是两个指针所“指向”的内存地址是否相同。这就像你问“这两本书是不是同一本?”你可能只是看它们的封面标题是否一样。在很多场景下,我们确实只需要知道两个

shared_ptr

是否指向了内存中的同一个对象实例。比如,你可能在遍历一个列表,想看看某个

shared_ptr

是否已经存在于列表中,此时比较

get()

返回的地址是最直接、效率也最高的做法。

然而,

std::owner_less

提供的所有权比较,则更像是问“这两本书是不是由同一个出版商、同一个作者创作的,即便它们的版本或装帧不同?”它关注的是更深层次的“身份”——控制块。一个经典的例子就是

shared_ptr

的别名构造函数(aliasing constructor)。

百度文心百中

百度文心百中

百度大模型语义搜索体验中心

百度文心百中 263

查看详情 百度文心百中

struct Resource {    int id;    std::string name;};struct Member {    int value;};// 假设Resource里有一个Member类型的成员struct ComplexResource {    int resource_id;    Member internal_member;};std::shared_ptr res_ptr(new ComplexResource{1, {100}});// 创建一个shared_ptr,它与res_ptr共享所有权,但指向的是res_ptr管理的对象的某个成员std::shared_ptr 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// 这表示它们在所有权层面上是等价的。

在这个例子中,

res_ptr

member_ptr

指向的内存地址截然不同,所以

==

比较会返回

false

。但它们却共享同一个控制块,意味着它们的生命周期是绑定在一起的,当

res_ptr

的引用计数归零时,

ComplexResource

对象才会被销毁。

member_ptr

仅仅是提供了一个指向

internal_member

的视图,但它本身并不拥有

internal_member

的独立生命周期。

std::owner_less

的存在,正是为了解决这种“指向不同,但管理同一份资源”的场景。它允许你在需要根据资源管理身份来区分对象时,能够有一个可靠的机制。这在将

shared_ptr

weak_ptr

作为键存储在

std::map

std::set

这样的有序关联容器中时尤为重要,因为这些容器需要一个稳定的、能提供严格弱序的比较器来正确地插入和查找元素。如果只用

operator==

来判断,上面的

res_ptr

member_ptr

就会被认为是两个不同的键,即便它们在逻辑上是关联到同一份核心资源的。

std::weak_ptr

如何参与所有权比较,它与

std::shared_ptr

有何异同?

std::weak_ptr

在所有权比较中扮演的角色,我觉得用“观察者”来形容最为贴切。它本身不拥有资源,只是对

std::shared_ptr

所管理资源的一个“弱引用”。这意味着

std::weak_ptr

不会增加资源的引用计数,因此它的存在不会阻止资源被销毁。

在比较行为上,

std::weak_ptr

std::shared_ptr

有着相似之处,也有其独特之处:

  1. 裸指针比较 (

    ==

    ,

    !=

    )

    std::weak_ptr

    同样重载了

    ==

    !=

    运算符,它们也是比较内部存储的裸指针地址。不过这里有个小细节:如果两个

    weak_ptr

    都已经过期(即它们所观察的

    shared_ptr

    已经销毁了资源),那么它们也会被认为是相等的,因为它们都指向了无效的地址(通常是

    nullptr

    )。这与

    shared_ptr

    略有不同,

    shared_ptr

    只有在

    get()

    返回相同地址时才相等。

  2. 所有权比较 (

    std::owner_less

    ):这才是

    std::weak_ptr

    在所有权比较中最有价值的地方。

    std::owner_less

    不仅可以比较两个

    shared_ptr

    ,两个

    weak_ptr

    ,甚至可以比较一个

    shared_ptr

    和一个

    weak_ptr

    ,来判断它们是否指向同一个控制块。

    想象这样一个场景:你有一个缓存系统,里面存储了资源的

    std::weak_ptr

    。当需要访问某个资源时,你会尝试

    lock()

    这个

    weak_ptr

    获得一个

    shared_ptr

    。但在某些情况下,你可能需要判断当前正在使用的

    shared_ptr

    是否与缓存中的某个

    weak_ptr

    观察的是同一个资源,即使缓存中的

    weak_ptr

    可能已经过期了。

    std::shared_ptr sp1(new int(10));std::weak_ptr wp1 = sp1;std::shared_ptr sp2(new int(20));std::weak_ptr wp2 = sp2;// sp1 和 wp1 共享同一个控制块bool same_owner_sp1_wp1 = !(std::owner_less<std::shared_ptr>()(sp1, wp1) || std::owner_less<std::shared_ptr>()(wp1, sp1)); // true// sp1 和 wp2 不共享同一个控制块bool same_owner_sp1_wp2 = !(std::owner_less<std::shared_ptr>()(sp1, wp2) || std::owner_less<std::shared_ptr>()(wp2, sp1)); // false// 让 sp1 过期,观察资源被销毁sp1.reset();// 此时 wp1 已经过期,但它仍然知道自己曾经观察的是哪个控制块// 它可以和另一个 shared_ptr 进行所有权比较,看它们是否“曾经”指向同一个资源std::shared_ptr sp_new(new int(30));bool same_owner_wp1_sp_new = !(std::owner_less<std::shared_ptr>()(wp1, sp_new) || std::owner_less<std::shared_ptr>()(sp_new, wp1)); // false
    std::weak_ptr

    能够通过

    std::owner_less

    参与所有权比较,这使得它在构建复杂的对象生命周期管理和缓存机制时非常强大。它允许我们在不影响资源生命周期的情况下,跟踪并识别资源的“身份”。

在实际开发中,何时以及如何正确使用智能指针的所有权比较?

在实际的C++开发中,正确理解并运用智能指针的所有权比较,能够帮助我们编写出更健壮、更高效的代码,尤其是在处理资源管理和对象生命周期时。

何时使用:

  1. 作为关联容器的键 (Key in Associative Containers):这是

    std::owner_less

    最常见且最重要的应用场景。如果你需要将

    std::shared_ptr

    std::weak_ptr

    对象作为

    std::map

    std::set

    的键,并且你希望这些容器能够根据智能指针所管理的“同一份资源”来唯一识别键,而不是仅仅根据裸指针地址,那么你就必须使用

    std::owner_less

    作为自定义比较器。

    • 示例场景:一个资源管理器,需要根据资源的唯一“身份”来存储和查找其元数据。
    • 错误做法:直接使用
      std::map<std::shared_ptr, MyMetadata>

      ,这会默认使用

      std::shared_ptr

      operator<

      ,而这个运算符在C++17之前是基于裸指针地址的,C++17之后才被定义为基于

      owner_less

      。为了兼容性和明确性,最好还是显式指定。

  2. 实现缓存机制 (Caching Mechanisms):在缓存系统中,你可能希望存储

    std::weak_ptr

    来避免持有资源导致其无法销毁,同时又需要能够快速判断一个新来的

    shared_ptr

    是否与缓存中某个

    weak_ptr

    指向同一份(或曾经指向同一份)资源。

    std::owner_less

    就能帮你完成这个任务。

  3. 调试与日志 (Debugging and Logging):当你在调试复杂的对象图或资源依赖关系时,可能需要验证两个不同的

    shared_ptr

    weak_ptr

    是否确实管理着同一个底层对象。

    std::owner_less

    提供了一个明确的语义来检查这种“所有权身份”的等价性。

  4. Observer 模式或事件系统 (Observer Pattern/Event Systems):在一些Observer模式的实现中,Subject可能持有对Observer的

    weak_ptr

    。当Subject需要通知Observer时,它会尝试

    lock()

    这些

    weak_ptr

    。如果系统中需要根据Observer的“身份”来注册或取消注册,

    std::owner_less

    可以帮助你识别同一Observer的不同

    weak_ptr

    实例。

如何正确使用:

  1. 对于
    std::unique_ptr

    :坚持使用

    ==

    !=

    运算符来比较它们所管理的裸指针地址。因为

    unique_ptr

    没有共享所有权的概念,其比较语义就是如此。

    
    

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1474000.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Code::Blocks IDE的下载安装和C++环境配置全过程
上一篇 2025年12月18日 21:04:44
C++结构体中的位域(bit-field)是用来做什么的
下一篇 2025年12月18日 21:04:58

相关推荐

  • 绝美后背! 日本妹子cos《寂静岭f》深水雏子

    绝美后背! 日本妹子cos《寂静岭f》深水雏子绝美后背! 日本妹子cos《寂静岭f》深水雏子绝美后背! 日本妹子cos《寂静岭f》深水雏子绝美后背! 日本妹子cos《寂静岭f》深水雏子

    《寂静岭f》女主角深水雏子近日在社交平台上引发热议,看似是普通的日本高中女生,实则性格果决、战斗力爆表。手持铁管正面硬刚女鬼的场面令人印象深刻,干脆利落的战斗风格让她迅速被玩家封神,成为《寂静岭》系列中最具冲击力的新角色之一。拥有30万粉丝的人气coser月海つくね(@XaiabP)也忍不住致敬这位…

    2026年9月24日 用户投稿
    100
  • 减少PHP与MySQL数据库通信的延迟

    减少php与mysql数据库通信的延迟可以通过以下策略:1. 优化数据库查询,使用索引提升查询速度;2. 减少数据库连接次数,使用连接池管理连接;3. 查询优化,使用explain分析查询计划;4. 使用缓存,如redis,减少数据库查询次数。这些方法能显著提升应用性能,但需权衡利弊,确保系统稳定性…

    2026年9月24日
    000
  • win10开机后黑屏只有鼠标怎么办_win10黑屏无桌面修复方案

    首先重启Windows资源管理器,若无效则更新显卡驱动,进入安全模式禁用启动项与服务,运行sfc和DISM修复系统文件,并检查User Profile Service等关键服务状态。 如果您成功启动Windows 10系统,但桌面无法正常加载,仅显示黑色屏幕和可移动的鼠标光标,这通常是由于系统关键进…

    2026年9月24日
    200
  • 讯维解决KVM鼠标不同步

    讯维解决KVM鼠标不同步讯维解决KVM鼠标不同步讯维解决KVM鼠标不同步讯维解决KVM鼠标不同步

    使用网络kvm时,常遇到本地鼠标与远程界面光标位置不一致的问题,即鼠标不同步现象,严重影响操作流畅性。可通过优化鼠标同步设置、更新驱动程序或选用兼容性更强的设备来有效改善。 1、配置运行Windows 2000操作系统的服务器环境 2、调整鼠标相关参数 3、点击开始菜单,进入控制面板,选择“鼠标”进…

    2026年9月24日 用户投稿
    900
  • 三星手机微信收款语音播报怎么开启?详细教程助你设置成功

    要让三星手机微信收款语音播报正常工作,需先检查微信内“收款到账语音提醒”是否开启,再确保手机系统中微信的通知权限完整开启、电池优化设为“不受限制”,同时确认媒体音量未静音、勿扰模式未启用;此外,定期清理缓存、保持应用与系统更新、避免第三方清理软件误杀后台,可保障通知长期稳定。 三星手机要开启微信收款…

    2026年9月24日
    300
  • 对于2K分辨率游戏玩家而言,中端显卡是否已能完全满足未来两三年的需求?

    中端显卡在2025年仍可满足2K游戏需求,关键在于选择12GB以上显存并支持DLSS 4或FSR 3.1技术的型号,如RTX 5060 Ti 16GB、RX 7700 XT或RX 6750 GRE 12GB,配合超分技术可在多数主流游戏中实现高帧率流畅体验。 对于2K分辨率的游戏玩家,中端显卡在20…

    2026年9月24日
    800
  • mac怎么分屏_mac分屏操作方法

    通过快捷键、拖拽或调整比例可高效使用Mac分屏功能。首先点击并按住绿色按钮选择窗口配对,或拖动窗口至屏幕边缘自动进入分屏;随后可调节分割线更改窗口比例;退出时点击顶部绿色按钮即可恢复普通模式。 如果您希望在使用 Mac 时提高多任务处理效率,可以通过分屏功能同时查看和操作两个应用程序。该功能允许用户…

    2026年9月24日
    100
  • 如何分析Linux进程内存 pmap内存映射检查方法

    如何分析Linux进程内存 pmap内存映射检查方法如何分析Linux进程内存 pmap内存映射检查方法如何分析Linux进程内存 pmap内存映射检查方法如何分析Linux进程内存 pmap内存映射检查方法

    要分析linux进程的内存,特别是利用pmap工具,核心操作是获取目标进程pid后执行pmap -x 。1. 获取pid可通过ps aux | grep your_process_name;2. 执行pmap -x 命令查看扩展格式信息,包括address、kbytes、rss、dirty、mode…

    2026年9月24日 用户投稿
    200
  • 如何实现Linux与Windows双系统引导管理?

    答案是先安装Windows再安装Linux,使用GRUB引导;需注意引导模式(UEFI/Legacy)与分区策略(ESP、/、swap、/home),并可通过Live USB修复GRUB。 实现Linux与Windows双系统引导管理,核心在于一个可靠的引导加载器,通常是Linux在安装时提供的GR…

    2026年9月24日
    000
  • 2025年生成漫画图片的AI工具Top10盘点

    2025年生成漫画图片的AI工具Top10盘点2025年生成漫画图片的AI工具Top10盘点2025年生成漫画图片的AI工具Top10盘点2025年生成漫画图片的AI工具Top10盘点

    2025年AI漫画工具已深度融入创作全流程,十大工具各具特色:ComiGenius Pro 3.0强于叙事连贯与情绪表达,MangaFlow AI专精日漫风格,PanelCraft AI优化分镜布局,StorySketcher 2025实现故事可视化,Artisan Studio X支持多风格模拟,…

    2026年9月24日 用户投稿
    200
  • VSCode如何优化多语言混编 VSCode复合工程项目的管理技巧

    #%#$#%@%@%$#%$#%#%#$%@_e2fc++805085e25c9761616c00e065bfe8处理多语言混编和复杂项目的核心策略是使用多根工作区(multi-root workspace),通过创建.code-workspace文件将不同语言或模块的目录统一管理,实现跨项目文件浏…

    2026年9月24日
    000
  • AI PC的概念是炒作还是未来趋势?

    AI PC正通过专用芯片、本地化智能和新交互模式重塑个人电脑。专用NPU算力突破50TOPS,使设备可高效运行图像识别、语音分析等AI任务,实现快速安全的本地处理;高通在骁龙X Elite上运行130亿参数大模型,微软Windows 11原生支持本地AI,让文档润色、图像修复等操作可在无网环境下完成…

    2026年9月24日
    200
  • 文字生成图片的AI工具2025十大好用推荐

    2025年热门AI文生图工具包括DALL-E 3、Midjourney、Stable Diffusion XL等,具备高图像质量、快速生成、强语义理解与精细风格控制,适用于不同用户需求,未来趋势指向更高清、更智能、更集成的创作生态。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使…

    2026年9月24日
    200
  • VSCode如何优化多项目切换 VSCode工作区快速跳转的实用技巧

    vscode优化多项目切换的核心是使用工作区功能并结合快捷键与插件。1. 创建工作区:通过“文件”→“将工作区另存为…”保存包含多个项目文件夹的.code-workspace文件;2. 配置工作区:在json格式的配置文件中定义folders和settings,如排除node_modules等无关文…

    2026年9月24日
    000
  • 处理PHP多线程的定时任务并行_优化php多线程怎么实现的定时任务执行

    PHP可通过多进程、消息队列等方式实现定时任务并行处理。1. 使用pthreads扩展(需ZTS支持)可在CLI环境实现多线程,但部署复杂;2. 利用pcntl_fork创建子进程是推荐方案,通过fork多个进程并行执行任务,适合CLI模式;3. 通过crontab同时触发多个独立脚本或使用exec…

    2026年9月24日
    200
  • 怎样处理C++中的野指针问题 空指针检测与防御性编程

    怎样处理C++中的野指针问题 空指针检测与防御性编程怎样处理C++中的野指针问题 空指针检测与防御性编程怎样处理C++中的野指针问题 空指针检测与防御性编程怎样处理C++中的野指针问题 空指针检测与防御性编程

    野指针难以发现是因为其指向已失效或非法内存,解引用会导致未定义行为。1. 初始化是关键防线,声明指针时必须赋初值或设为nullptr;2. 使用智能指针std::unique_ptr和std::shared_ptr可自动管理内存生命周期,避免手动delete遗漏;3. 防御性编程要求每次使用指针前进…

    2026年9月24日 用户投稿
    200
  • 360浏览器怎么关闭网页预加载_360浏览器禁用后台预加载提升性能设置

    关闭360浏览器预加载功能可减少资源占用,依次通过设置中心关闭网页预加载、禁用加速功能、修改隐私与安全设置限制后台行为。 如果您发现360浏览器在后台自动预加载网页,导致系统资源占用较高或网络变慢,可能是由于浏览器的智能预加载功能正在运行。该功能会提前加载您可能访问的网页内容以提升浏览速度,但同时也…

    2026年9月24日
    100
  • VSCode如何实现移动端调试 VSCode连接Android/iOS设备的技巧

    vscode本身不支持移动端调试,但可通过插件和工具间接实现。1. 调试android应用时,需开启设备开发者模式和usb调试,连接电脑后通过chrome浏览器访问chrome://inspect/#devices,使用chrome devtools调试webview;可配合vscode的debug…

    2026年9月24日
    000
  • VS Code工作台UI:自定义CSS与视图容器配置

    可通过扩展和配置自定义VS Code UI:1. 使用Custom CSS and JS Loader注入CSS修改外观,但有风险;2. 推荐创建Color Theme扩展,通过JSON定义主题颜色;3. 利用viewsContainers在活动栏添加自定义容器;4. 用户可设置view.locat…

    2026年9月24日
    000
  • OmniHuman-1.5— 字节推出的数字人动画生成模型

    OmniHuman-1.5— 字节推出的数字人动画生成模型OmniHuman-1.5— 字节推出的数字人动画生成模型OmniHuman-1.5— 字节推出的数字人动画生成模型OmniHuman-1.5— 字节推出的数字人动画生成模型

    ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ 怪兽AI数字人 数字人短视频创作,数字人直播,实时驱动数字人 44 查看详情 OmniHuman-1.5是什么 omnihuman-1.5 是由字节跳动推出的一款前沿ai模型,能够基于单张静态图…

    2026年9月24日 用户投稿
    100

发表回复

登录后才能评论
关注微信