C++ std::string的引用计数

C++ std::string的引用计数,c++,string,g++,stdstring,reference-counting,C++,String,G++,Stdstring,Reference Counting,我正在看basic_string(与g++4.2.1捆绑在一起)的代码。复制构造函数使用grab()函数“获取”字符串的副本(增加其引用计数): 只有当两个字符串的分配器相同时,才会增加引用计数——这是有意义的。但是,复制构造函数是: basic_string(const basic_string& __str) : _M_dataplus(__str._M_rep()->_M_grab(_Alloc(__str.get_allocator()), __str.get_alloca

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

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

basic_string(const basic_string& __str)
: _M_dataplus(__str._M_rep()->_M_grab(_Alloc(__str.get_allocator()), __str.get_allocator()),
              __str.get_allocator())
{ }
传递给
\u M_grab()
的第一个分配器是第二个分配器的副本。为什么?
allocator
operator==()
可能返回false的唯一方法是用户使用自定义分配器。然而,即使这是真的,您也会认为复制的分配器会与其原始分配器进行比较,对吗?因此:

  • 为什么要比较分配器呢
  • 为什么复制构造一个分配器并将复制与原始进行比较
  • 将副本与原始副本进行比较会返回false的用例是什么
  • 更新
    是的,
    \u M\u grab()
    用于另一个位置:分配。在这种情况下,传递给
    \u M\u grab()
    的分配器是不同的。好的但是似乎仍然没有理由复制构造函数,然后比较构造函数中
    string

    的分配器。我知道关于GCC团队的推理,但以下是我的假设:

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

  • 所以它可以重用_M_grab()

  • 不应该发生吗

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

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

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

  • 更新

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


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

    我在这里看不到其余的代码,但真正的实用程序是否可能是在从其他地方调用
    \u m_grab()
    时使用的,而在这里,完成分配器的额外副本只是为了查看分配器是否都是副本可构造的,以及副本比较是否相等?显然,如果第一个不正确,调用甚至不会编译,但如果后一个不正确,资源管理仍会正常运行。@seh:您的“后一个”案例有一定道理,但我想不出一个副本构造的分配器与原始分配器相比不相等的用例,这似乎是一个非常奇怪的案例。然而,这可能并不罕见,因为这个字符串类的作者考虑到了这一点。所以我很好奇这种情况可能是什么。如果#3总是正确的,那么为什么还要费心去复制它呢?为什么不把这两个参数的u str.get_allocator()传递给_M_grab()?@Paul:你说得对;看起来显式副本是不必要的,但无害的
    get_allocator()
    无论如何都会返回一个副本。我的问题更多的是明显不必要的副本构造,而不是比较(您在回复我的评论时提到了这一点);因此,您以后的“更新”似乎有点不合逻辑。
    basic_string(const basic_string& __str)
    : _M_dataplus(__str._M_rep()->_M_grab(_Alloc(__str.get_allocator()), __str.get_allocator()),
                  __str.get_allocator())
    { }