为何std::string实例地址与c_str()返回指针地址一致?
为什么std::string实例地址和c_str()返回地址完全相同?
当我们用&获取std::string实例的地址时,发现该地址和调用c_str()返回的指针地址完全匹配,但我们知道c_str()返回的是std::string内部存储的字符数组地址,并非实例本身的地址,这一现象是怎么实现的?
示例代码:
#include <string> #include <iostream> int main(int argc, char const *argv[]) { std::string s = "Hello, World!"; auto addr = &s; auto addr2 = s.c_str(); std::cout << std::hex << addr << std::endl; std::cout << std::hex << reinterpret_cast<const void*>(addr2) << std::endl; if ((void*)addr == (void*)addr2) { std::cout << "Equal" << std::endl; } else { std::cout << "Not equal" << std::endl; } return 0; }
原因解析:小字符串优化(SSO)
这是标准库std::string实现中**小字符串优化(Small String Optimization, SSO)**带来的结果:
- 大部分现代C标准库(比如GCC的libstdc、Clang的libc++)都会针对短字符串做SSO优化:当字符串长度小于等于某个阈值(通常是15字节,需预留1字节存终止符
'\0',不同实现阈值可能有差异,比如MSVC是22字节),字符串的字符会直接存储在std::string对象自身的内存空间里,不会去堆上分配额外内存。 - 这类实现会把
std::string对象的内存布局设计成:当启用SSO时,对象的起始位置就是存储短字符串的缓冲区。这时候&s(std::string实例的地址)自然就等于缓冲区的起始地址,也就是c_str()返回的指针地址。 - 一旦字符串长度超过SSO阈值,
std::string就会在堆上分配内存存储字符,此时c_str()返回的是堆内存的地址,和&s(对象自身地址)就会完全不同。
你可以做个验证:把示例中的字符串改成足够长的内容(比如std::string s = "Hello, World! This is a very long string that will exceed the SSO limit of most implementations.";),再运行代码,就能看到两个地址不再相等。
内容的提问来源于stack exchange,提问作者JF4
相关产品推荐
相关产品推荐

