当前位置: 首页 > 知识库问答 >
问题:

有d::shared_ptr的非原子等价物吗?为什么里没有?

李勇
2023-03-14

这是一个两部分的问题,所有关于std::shared_ptr的原子性:

1.据我所知,std::shared_ptr中唯一聪明的指针

2.我理解为什么std::shared_ptr是原子的;它有点好。然而,这并不适合每种情况,而且C在历史上有“只为你使用的东西付费”的咒语如果我没有使用多个线程,或者如果我使用多个线程,但没有跨线程共享指针所有权,原子智能指针是多余的。我的第二个问题是为什么C 11中没有提供std::shared_ptr的非原子版本?(假设有原因)(如果答案只是“从来没有考虑过非原子版本”或者“从来没有人要求非原子版本”,那很好!)。

关于问题#2,我想知道是否有人提出过非原子版本的shared\u ptr(要么是为了推进,要么是为了标准委员会)(不是为了取代原子版本的shared\u ptr,而是为了与之共存),但它因特定原因被否决了。


共有3个答案

侯沈义
2023-03-14

我的第二个问题是为什么C11没有提供d::shared_ptr的非原子版本?(假设有一个为什么)。

人们可以很容易地问为什么没有侵入性指针,或者任何其他可能的共享指针变体。

Boost传下来的shared_ptr的设计旨在创建智能指针的最低标准通用语言。一般来说,你可以把它从墙上拉下来使用。它将被广泛应用于各种各样的应用中。你可以把它放在一个界面上,很有可能好人会愿意使用它。

线程在未来只会越来越普遍。事实上,随着时间的推移,线程通常是实现性能的主要手段之一。需要基本的智能指针来完成支持线程所需的最低限度工作,这有助于实现这一目标。

将六个智能指针(它们之间有微小的变化)转储到标准中,或者更糟糕的是,将基于策略的智能指针转储到标准中,将是非常糟糕的。每个人都会选择他们最喜欢的指针,而放弃所有其他指针。没有人能和其他人交流。这就像当前使用C字符串的情况一样,每个人都有自己的类型。更糟糕的是,使用字符串的互操作比智能指针类之间的互操作容易得多。

Boost和委员会选择了一个特定的智能指针来使用。它提供了功能的良好平衡,在实践中得到了广泛和普遍的应用。

std::vector在某些情况下与裸阵列相比也有一些低效。它有一定的局限性;有些用户确实希望在不使用抛出分配器的情况下对向量的大小有一个硬限制。然而,委员会并没有将向量设计成每个人的一切。它被设计为大多数应用程序的良好默认设置。对于那些无法使用它的人,可以编写一个适合他们需要的替代方案。

如果shared\ptr的原子性是一个负担,那么就如同智能指针一样。再者,人们也会考虑不要复制他们这么多。

欧阳斌
2023-03-14

Howard已经很好地回答了这个问题,Nicol就使用一个标准的共享指针类型而不是许多不兼容的指针类型的好处提出了一些好的观点。

虽然我完全同意委员会的决定,但我确实认为在特殊情况下使用不同步的shared_ptr类型有一些好处,所以我已经研究了几次这个话题。

如果我没有使用多个线程,或者如果我使用多个线程但没有在线程之间共享指针所有权,那么原子智能指针就太过分了。

当您的程序不使用多线程共享时,使用GCC时,ptr不会对refcount使用原子操作。这是通过通过包装函数更新引用计数来完成的,包装函数检测程序是否是多线程的(在GNU/Linux上,这是通过检查Glibc中的一个特殊变量来完成的,该变量表示程序是否是单线程的[1]),并相应地分派到原子或非原子操作。

很多年前我意识到,因为GCC的共享

template<typename T>
  using shared_ptr_unsynchronized = std::__shared_ptr<T, __gnu_cxx::_S_single>;

此类型不能与std::互操作shared_ptr

这当然是完全不可移植的,但有时也可以。如果与其他未同步的代码共享,则

[1]在Glibc 2.33添加该变量之前,包装函数将检测程序是否链接到libpthread.so,作为检查单线程和多线程的不完美方法。

傅明知
2023-03-14

1.我想知道是否有std::shared_ptr的非原子版本可用

本标准未提供。很可能有一个由“第三方”库提供。事实上,在C 11之前和Boost之前,似乎每个人都编写了自己的引用计数智能指针(包括我自己)。

2.我的第二个问题是为什么C11没有提供d::shared_ptr的非原子版本?

这个问题在2010年的Rapperswil会议上进行了讨论。瑞士的国家机构评论20介绍了这一主题。辩论双方都有强有力的论点,包括你在问题中提出的论点。然而,在讨论结束时,投票以压倒性多数(但并非一致)反对添加非同步(非原子)版本的shared\u ptr

反对的理由包括:

>

  • 使用不同步shared_ptr编写的代码最终可能会在以后的线程代码中使用,最终导致难以调试的问题而没有警告。

    有一个“通用”shared_ptr,这是参考计数中流量的“单向”,有好处:从最初的提议来看:

    具有相同的对象类型,无论使用的功能如何,这极大地促进了库之间的互操作性,包括第三方库。

    原子经济的成本虽然不是零,但也不是压倒性的。通过使用不需要使用原子操作的移动构造和移动分配,降低了成本。这类操作通常在向量中使用

    如果人们真的想写非原子引用计数的智能指针,那么没有什么可以阻止他们写自己的智能指针。

    当天,拉帕斯维尔LWG的最后一句话是:

    拒绝CH 20。目前没有做出改变的共识。

  •  类似资料:
    • 我在角度使用日期范围选择器。 当我点击这个按钮时,我得到下拉菜单,用一个Apply按钮选择日期范围,这个按钮有一个类“applyBtn”。 在 JQuery 中有一个选项 来获取 函数。我不能写在打字稿中是否有的等价物? 我想要这样的东西,

    • 我仍然在学习和试验JavaFX中的GUIs,我似乎无法得到我所希望的“外观”…我试图在一个面板中分组几个标签,然后在另一个面板中添加另一个标签。但我似乎不知道如何在JavaFX中正确使用“JPanels”? 如有任何帮助,将不胜感激 编辑:这是我试图通过尝试不同的布局来实现的,但运气仍然不好

    • 在Mac和Windows上,可以使用 <罢工> (替换 )和 (替换 ) (Docker 18.03+)位于容器内。 对于Linux来说,有没有一个可以在不传递env变量或使用各种CLI命令提取它的情况下开箱即用的方法?

    • 我们有以下场景:使用Sonarqube扫描Windows10中的两个项目。 null 提前谢了。

    • 我在一个Spring Boot项目中有一个rest控制器API。我需要添加一个通用函数,例如,在控制器中的所有路由之前验证每个传入请求的令牌,而不是为每个路由单独调用相同的函数。有没有一种方法可以通过基于@RestController的路由而不是通过web flux处理程序和路由器的方式来实现这一点? 编辑:是否有一种方法只对某些路由而不是所有传入请求使用拦截器?

    • 我看到Kotlin有,它们相当于Java中的。 现在我想知道,是否有等价于Java的?