贝利信息

c++的std::string和std::vector在内存布局上有什么区别? (连续内存模型)

日期:2026-01-22 00:00 / 作者:穿越時空
C++11起std::string内存连续但含SSO和预留空间,而std::vector严格物理连续且无字符串语义约束;二者不可互换使用。

std::string 的内存布局不保证连续(C++11 之前)

在 C++11 标准之前,std::string 的实现允许使用“写时复制”(Copy-on-Write),底层缓冲区甚至可能被多个 std::string 对象共享,此时 &str[0] 不一定指向真正可写的连续区域。C++11 明确要求 std::string 必须满足“连续存储”——即 &str[0] + i == &str[i] 对所有有效 i 成立,但该连续块仍可能包含未使用的预留空间(capacity()size()),且其起始地址不一定等于堆分配的原始指针(例如 small string optimization 会把短字符串存在对象内部)。

std::vector 的内存布局严格连续且透明

std::vector 的标准要求其元素必须存储在单一、动态分配的连续内存块中,且 &v[0] 等价于 v.data

()(只要 v.size() > 0)。这个连续性是强制的、可依赖的,也是它支持传给 C 接口(如 read(fd, v.data(), v.size()))的根本原因。

为什么不能把 std::string 当作 std::vector 用?

表面看都是字符容器,但二者抽象层级和内存契约不同。你无法安全地对 std::stringresize() 后直接用 data() 当裸缓冲区填入二进制数据,因为:

std::string s;
s.resize(10); // size=10, capacity≥10
s[0] = 'x';   // OK,但 s 仍是合法字符串
// 若后续调用 s.c_str(),它保证返回以 \0 结尾的 C 字符串
// 这个 \0 可能位于 s[10](额外分配的字节),也可能复用 capacity 中的闲置位置

需要连续 char 缓冲区时该选哪个?

取决于用途:

最易被忽略的一点:std::string 的连续性是“逻辑连续”,而 std::vector 的连续性是“物理+语义连续”。前者服务于字符串语义,后者服务于通用容器契约。混用它们的底层指针,迟早会在某个编译器或 STL 版本上出问题。