std::string::size() 是如何实现的

How is std::string::size() implemented?

本文关键字:实现 何实现 string std size      更新时间:2023-10-16
cout << sizeof(std::string) << endl;

在我的 8 位机器上的结果是 64,这与 sizeof(char*) 相同,所以我假设字符串类只存储char*。那么,大小函数是如何实现的呢? 它是否使用strlen(因为它不存储实际大小或指向结束字节的指针)?

在此页面上,它显示大小函数具有恒定的时间复杂度,所以我很困惑。 在另一个页面上,某人的字符串大小更大。

我在 Fedora 64 位上使用 GCC 4.7.1。

对此可能有很多解释。仅仅因为std::string碰巧存储了一个指针而没有其他东西并不意味着它一定是指向受控序列char *指针。你为什么会得出这个结论?

很容易发现,您的std::string是一个 PImpl 样式的包装器,用于指向某个内部对象的指针,该对象存储所有内部家庭数据,包括char *指针、长度和其他任何必要的内容。这样,内部对象可以任意大,而不会对std::string本身的大小产生任何影响。例如,为了便于快速引用计数复制,在某些实现中,std::string可以实现类似于std::shared_ptr。即 在这种情况下,std::string基本上会变成类似std::shared_ptr<std::string_impl>的东西,并添加了写入时复制语义。

目标"字符串

实现"对象甚至可能使用"struct hack"风格的方法来存储实际字符串,这意味着它可能会在末尾将整个字符串嵌入到自身中,而不是存储指针char *

查看 libstdc++ 的 doxygen 文档:

_CharT* _M_p; // The actual data

假设 std::basic_string<char>_M_p 是指向实际数据的char*指针,因此这就是您获得8的原因。

它甚至说:

其中_M_p指向字符串中的第一个字符,并且您 将其转换为指向_Rep的指针并减去 1 以获得指向 页眉。

因此,它在存储字符串数据之前将指向实际表示形式(容量、长度等)的指针隐藏在内存块中。

然后,有以下成员函数来获取表示形式:

Rep* _M_rep() const
{ return &((reinterpret_cast<_Rep*> (_M_data()))[-1]); }

然后他们这样称呼它,例如_M_rep()->_M_length;得到size

你认为std::string是char*的假设是错误的。以下是 sizeof(std::string)==sizeof(char*) 的 q 几个可能的实现之一:

struct std::string
{
    string_implementation
    {
        size_t size;
        size_t buffer_size;
        char_traits whatever;
        char *buffer; // Here is your actual string!
    };
    string_implementation *ptr;
}

std::stringstd::basic_string<char>typdefbasic_string(在我的机器上)在文件/usr/include/c++/4.4/bits/basic_string.h中定义。该文件中有很多间接寻址,但粗略地std::string存储指向实际数据的指针

// Use empty-base optimization: http://www.cantrip.org/emptyopt.html
      struct _Alloc_hider : _Alloc
      {
    _Alloc_hider(_CharT* __dat, const _Alloc& __a)
    : _Alloc(__a), _M_p(__dat) { }
    _CharT* _M_p; // The actual data.
      };

这就是你观察到这种行为的原因。可以强制转换此指针以获取指向描述已知字符串属性(位于实际数据前面)的结构的指针:

  struct _Rep_base
  {
size_type       _M_length;
size_type       _M_capacity;
_Atomic_word        _M_refcount;
  };
_Rep* _M_rep() const
      { return &((reinterpret_cast<_Rep*> (_M_data()))[-1]); }