繁体   English   中英

std :: shared_ptr中的最大引用计数是多少? 如果你试图超过它会发生什么?

What is the maximum reference count in std::shared_ptr? What happens if you try to exceed it?

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

如果我们假设std::shared_ptr存储了一个引用计数(我意识到标准不需要,但我不知道任何没有的实现),那个引用计数的位数有限,这意味着有支持的最大引用数。 这导致了两个问题:

  • 这个最大值是多少?
  • 如果你试图超过它会发生什么(例如,通过复制引用具有最大引用计数的对象的std :: shared_ptr)? 请注意, std::shared_ptr的复制构造函数声明为noexcept

该标准是否对这两个问题都有所了解? 常见的实现如何,例如gcc,MSVC,Boost?

5 个回复

我们可以从shared_ptr::use_count()函数中获取一些信息。 §20.7.2.2.5说:

long use_count() const noexcept;

返回: shared_ptr对象的数量, *this包括*this对象,与*this共享所有权,或者当*this为空时为0

[注意: use_count()不一定有效。-end note]

乍一看, long回报类型似乎回答了第一个问题。 然而,这个注释似乎暗示shared_ptr可以自由地使用它想要的任何类型的引用计数,包括像引用列表之类的东西。 如果是这种情况,那么理论上就没有最大参考计数(尽管肯定存在实际限制)。

没有其他参考限制我可以找到的同一对象的引用数量。

值得注意的是, use_count被记录为不抛出和(显然)正确报告计数; 除非实施确实使用long成员进行计数,否则我看不出这两种方法在任何时候都能在理论上得到保证。

我不确定标准的含义,但实际上看看它:

引用计数很可能是某种std::size_t变量。 此变量在32位环境中最多可保持-1+2^32 ,在64位环境中最多可保持-1+2^64

现在想象这个变量要达到这个值会发生什么:你需要2 ^ 32或2 ^ 64个shared_ptr实例。 好多啊。 事实上,在你达到这个数字之前很久就会耗尽所有内存,因为一个shared_ptr大约是8/16字节。

因此,如果refcount变量的大小足够大,则您不太可能达到引用计数的限制。

标准没有说; 正如你所说,它甚至不需要引用计数。 另一方面,标准(或至少在C标准中)存在(或曾经)超出实施限制的陈述是未定义的行为。 所以这几乎肯定是官方的答案。

在实践中,我希望大多数实现将计数保持为size_tptrdiff_t 在具有平面寻址的机器上,这几乎意味着您无法创建足够的引用来导致溢出。 (在这样的机器上,单个对象可以占用所有内存,而size_tptrdiff_t具有与指针相同的大小。由于每个引用计数指针都有一个不同的地址,所以永远不会超过指针。)然而,在具有分段架构的机器上,可以想象溢出。

正如Jon指出的那样,标准还要求std::shared_ptr::use_count()返回long 我不确定这里的基本原理: size_tptrdiff_t在这里会更有意义。 但是,如果实现对引用计数使用不同的类型,可能会将转换为long的规则应用:“如果可以在目标类型(和位字段宽度)中表示,则值不会更改;否则,值是实现定义的。“ (C标准使这一点更加清晰:“实现定义的值”可以是一个信号。)

您可以通过使用placement new实例化共享指针并从不删除它们来了解将会发生什么。 然后,您可以轻松地达到32位限制。

在C ++ 11标准规定long的的返回类型use_count()观察者的功能,但没有明确指定如果实现必须支持多达2^(sizeof(long)*8-1)-1共享所有权。

它也没有指定引用计数器溢出时会发生什么。

boost::shared_ptr实现(例如Fedora 23上的1.58,x86-64)内部使用32位计数器,不检查溢出。

这意味着:

  1. 最大引用计数为2^31-1
  2. 如果您有溢出和释放所有权,您最终可能会遇到一些免费使用后的问题

由于boost使用不同平台的不同低级特化,您可以通过在*add_ref_lock设置断点来验证详细信息 - 在Fedora 23 / x86-64上,您将在此处停止:

/usr/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp
[..]
int use_count_;        // #shared
int weak_count_;       // #weak + (#shared != 0)
[..]
bool add_ref_lock() // true on success
{
    return atomic_conditional_increment( &use_count_ ) != 0;
}

也可以看看:

GNU STL(libstdc ++)shared_pointer实现基于Boost 1.32 one并且也存在此问题(在Fedora 23 / x86-64上) - 其中_Atomic_word类型用于引用计数。 它也是'仅'32位,不检查溢出。

相比之下,LLVM libc ++ shared_ptr实现使用long参考计数器,即在x64-64等LP64平台上,您可以在最多2^63-1所有者之间共享一个对象。

1 调用* shared_ptr *的方法-引用计数会怎样?

我正在尝试找出一个令人讨厌的错误,其中一个对象在地图内时会自发地损坏,经过几个小时的调试,我想我可能还没有完全掌握std :: shared_ptr的想法。 这里是上下文:在一个方法中,我声明一个std :: shared_ptr并将其初始化为指向当前对象的一个​​副本(由new创建)。 ...

2 如果我将std :: shared_ptr重置为自身会发生什么

以下程序崩溃时出现错误的glibc双重自由错误: 从这里我得到以下输出(后跟glibc错误): 很明显,在这种情况下,对象被销毁两次。 一旦通过重置,一次由std::shared_ptr超出范围。 这实际上是我所期待的。 但是在cppreference上我找到了以下文本 ...

3 如果我指定`shared_ptr,会怎样? &`另一个参考

我已经实现了责任链设计模式,并且链中的每个元素都是shared_ptr 。 在这种情况下,我想有first作为链的开始和last和链的一端能够添加使用新链ITMS last 。 在下面的函数中, link是作为局部变量创建的当前链元素,以及我使用以下函数添加到链中的元素: 使用所有引 ...

4 使用 std::shared_ptr 接收变量作为引用的优缺点是什么?

我只是想知道将在func1内部创建的指针变量传递给调用者( func2 )的以下方法是否是正确的方法。 如果这是正确的,它会在返回func2时释放内存吗? 如果这是一个坏主意,那是为什么? 这是一个简化的代码。 我假设d的大小很大(例如图像)。 补充:我意识到以下也有效。 什么将是每种方法的利 ...

8 std :: shared_ptr有什么问题 >

我的印象是std :: shared_ptr超出范围时不会释放内存。 下面是我的测试代码。 你能建议我做错了什么吗? 我使用gtest进行测试。 执行此测试时,我可以看到内存不断消耗。 我使用Microsoft VC ++ 2013。 ...

9 在制作shared_ptr的副本时会发生什么?

我想了解如何在管理对象的引用计数shared_ptr时,受影响shared_ptr被分配到另一个。 我在C ++入门第5版中遇到以下声明: 例如,与shared_ptr关联的计数器在...时使用它作为赋值的右手操作数 ... 当我们为shared_ptr分配新值时 , 计数器会递 ...

10 use_count std :: shared_ptr的所有增加方式是什么?

我有两个指向同一个int shared_ptr ,即在它们上调用get()返回相同的地址。 但是在它们上面调用use_count()返回1 。 当它们中的最后一个超出范围时,它会尝试释放已经被另一个释放的内存,从而导致双重释放运行时错误: 在此变体中使用显式声明的原始指针也会发生同样 ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2021 STACKOOM.COM