为何长度小于16字节的std::string不触发重载new?内存分配位置在哪?
关于std::string短字符串内存分配的问题
基础追踪代码
我们通过重载new运算符来追踪std::string的内存分配行为,代码如下:
static uint32_t s_AllocCount = 0; // Overload of new operator. void* operator new(size_t size) { s_AllocCount++; std::cout << "Allocating " << size << " bytes\n"; return malloc(size); }
示例1:长字符串初始化
当使用较长字符串初始化std::string时:
int main() { std::string name = "Hello World 1234"; std::cout<<"No. of allocations="<<s_AllocCount<<std::endl; return 0; }
输出
Allocating 17 bytes No. of allocations=1
示例2:短字符串初始化
当使用较短字符串初始化std::string时:
int main() { std::string name = "Hello World"; std::cout<<"No. of allocations="<<s_AllocCount<<std::endl; return 0; }
输出
No. of allocations=0
问题
为何在示例2中,长度小于16字节的std::string未调用重载的new运算符?该字符串的内存初始化发生在何处?
解答
这是因为标准库的std::string实现普遍采用了**短字符串优化(SSO,Short String Optimization)**机制:
- 当字符串的长度小于某个阈值(多数实现中是15字节,加上结束符共16字节)时,字符串的内容会直接存储在
std::string对象本身的内部缓冲区中,不需要向堆内存申请空间。 - 只有当字符串长度超过这个内部缓冲区的容量时,
std::string才会通过new运算符在堆上分配内存来存储字符串内容,此时才会触发我们重载的operator new。
简单来说,示例2中的短字符串直接存在std::string对象自身的内存里,完全不需要堆分配,所以不会调用new,自然不会被我们的追踪代码统计到。
内容的提问来源于stack exchange,提问作者Santosh Sahu
相关产品推荐
相关产品推荐

