cout << sizeof(std::string) << endl;
结果是 8 在我的 64 位机器上,这与 相同sizeof(char*)
,所以我假设字符串类只存储char*
. 那么,size函数是如何实现的呢?它是否在使用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::string
是一个typdef
for std::basic_string<char>
,并且basic_string
在文件中定义(在我的机器上)/usr/include/c++/4.4/bits/basic_string.h
。该文件中有很多间接性,但粗略的 speekingstd::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]); }