这是一个简短的程序,帮助您探索std::string
的两种内存使用方式:栈和堆。
#include <string>
#include <new>
#include <cstdio>
#include <cstdlib>
std::size_t allocated = 0;
void* operator new (size_t sz)
{
void* p = std::malloc(sz);
allocated += sz;
return p;
}
void operator delete(void* p) noexcept
{
return std::free(p);
}
int
main()
{
allocated = 0;
std::string s("hi");
std::printf("stack space = %zu, heap space = %zu, capacity = %zu\n",
sizeof(s), allocated, s.capacity());
}
使用
http://melpon.org/wandbox/ 很容易获得不同编译器/库组合的输出,例如:
gcc 4.9.1:
stack space = 8, heap space = 27, capacity = 2
gcc 5.0.0:
stack space = 32, heap space = 0, capacity = 15
clang/libc++:
stack space = 24, heap space = 0, capacity = 22
VS-2015:
stack space = 32, heap space = 0, capacity = 15
上面的输出还显示了
capacity
,它是一个度量标准,表示字符串在必须从堆中分配新的、更大的缓冲区之前可以容纳多少个
char
。对于gcc-5.0、libc++和VS-2015实现,这是短字符串缓冲区的度量标准。也就是说,在栈上分配大小缓冲区来保存短字符串,从而避免更昂贵的堆分配。
看起来libc++实现具有最小的(栈使用)短字符串实现之一,但却包含最大的短字符串缓冲区之一。如果你计算
总内存使用量(栈+堆),libc++在这4种实现中对于这个2字符字符串具有最小的总内存使用量。
值得注意的是,所有这些测量都是在64位平台上进行的。在32位上,libc++的栈使用将降至12,小字符串缓冲区将降至10。我不知道其他实现在32位平台上的行为,但你可以使用上述代码来找出答案。(最后一行引用自
http://webcompiler.cloudapp.net)
std::string
实现不符合C++11标准,而是使用了写时复制的实现方式,从而带来了尺寸上的节省。请重新运行您的libstdc++测试,使用vstring
进行比较并查看结果。 - Praetoriansizeof(std::string)
并不代表字符串占用的所有内存,而仅代表字符串类所占用的内存(例如,在堆栈上分配的字符串),并且不包括它所指向的任何数据结构。 - EyasSH__gnu_cxx::__vstring
,则结果会有很大的不同。而EyasSH所说的是,std::string
对象的大小不受其管理的字符串长度的影响。 - Praetorian