std::string::size() 是如何实现的
How is std::string::size() implemented?
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::string
是std::basic_string<char>
的typdef
,basic_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]); }
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 用于AVX的ln(x)的实现,m256
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 如何实现内部实现依赖于模板参数的类
- 我的 PRNG 实现与我尝试复制的实现有何不同?