std::string 的引用计数

Posted

技术标签:

【中文标题】std::string 的引用计数【英文标题】:Reference-counting of std::string 【发布时间】:2010-07-28 16:03:01 【问题描述】:

我正在查看 basic_string 的代码(与 g++ 4.2.1 捆绑在一起)。复制构造函数使用grab() 函数来“获取”字符串的副本(增加其引用计数):

_CharT* _M_grab( const _Alloc& __alloc1, const _Alloc& __alloc2 ) 
  return (!_M_is_leaked() && __alloc1 == __alloc2) ? _M_refcopy() : _M_clone(__alloc1);

只有当两个字符串的分配器相同时才会增加引用计数——这很有意义。但是,复制构造函数是:

basic_string(const basic_string& __str)
: _M_dataplus(__str._M_rep()->_M_grab(_Alloc(__str.get_allocator()), __str.get_allocator()),
              __str.get_allocator())
 

传递给_M_grab() 的第一个分配器是第二个的副本。为什么? operator==() for allocator 可能返回 false 的唯一方法是用户使用自定义分配器。但是,即使这是真的,您也会认为复制的分配器将与其原始分配器进行比较,对吗?所以:

    为什么要比较分配器? 为什么要复制构造分配器并将副本与原始文件进行比较? 将副本与其原件进行比较会返回 false 的用例是什么?

更新

是的,_M_grab() 用于另一个地方:分配。在这种情况下,传递给_M_grab() 的分配器是不同的。美好的。但似乎仍然没有理由同时复制构造,然后比较 string构造函数 中的分配器。

【问题讨论】:

我在这里看不到其余的代码,但是当_M_grab()从其他地方被调用时,真正的实用程序是否可能是,这里分配器的额外副本是只是为了看看分配器是否都是可复制的以及副本是否比较相等?显然,如果第一个不正确,调用甚至不会编译,但如果后者不正确,资源管理仍然会正常运行。 @seh:您的“后一种”情况是有道理的,但我想不出一个用例,其中复制构造的分配器与原始分配器相比 - 似乎非常奇怪的情况。但是,这可能并不罕见,因为这个字符串类的作者考虑了它。所以我很好奇这种情况可能是什么。 【参考方案1】:

我知道 zip 关于 GCC 团队的推理,但这是我的假设:

    用于调试?分配器必须相同。

    所以它可以重用_M_grab()?

    永远不应该发生?

【讨论】:

【参考方案2】:

    如果从一个分配器分配的对象可以与另一个释放,则分配器比较相等。如果是这样,那么两个字符串可以共享对同一个分配器的引用;否则,每个都需要自己的分配器。

    比较发生在_M_grab 内,在这种特殊情况下,它不知道一个参数是从另一个参数复制构造的。 _M_grab 也从 assign 调用,其中两个字符串可能有不同的分配器。

    分配器应始终与自身的副本进行比较。

更新

但似乎仍然没有理由同时复制构造,然后在构造函数中比较分配器以获取字符串。

实现两个几乎相同的_M_grab() 版本来避免不必要的比较(对于大多数分配器)无论如何都会在编译时发生,也没有特别好的理由。也许你认为这样的微优化是可取的;显然这段代码的作者没有。

【讨论】:

如果#3 总是正确的,那么为什么还要复制构造它呢?为什么不简单地将两个参数的 __str.get_allocator() 传递给 _M_grab() ? @Paul:你是对的;看起来显式副本是不必要的,但无害。 get_allocator() 无论如何都会返回一个副本。 我的问题更多是明显不必要的复制结构,而不是比较(您在回复我的评论时提到);因此,您以后的“更新”似乎有点不合情理。

以上是关于std::string 的引用计数的主要内容,如果未能解决你的问题,请参考以下文章

swift进阶七:引用计数(Strong、Unowned、Weak)

Netty引用计数

python 10

python 基础之引用计数

引用计数器

引用计数--1