预分配内存是避免 O(n²) 性能退化的关键:reserve() 必须在循环外一次性调用,单字符重复用 std::string(count, ch),多字符重复避免 substr() 拷贝而用 append(s, pos, len) 或 string_view。

大规模重复连接必须预分配内存,否则 append() 或 += 会退化成 O(n²) 行为——这不是“慢一点”,而是数据量翻倍时耗时可能翻 4 倍以上。
为什么 reserve() 必须在循环外一次性调用
常见错误是每次追加前都写 result.reserve(result.size() + add_len)。这等于没 reserve():容量仍按指数增长,realloc 次数不减。
- 真正有效的做法是把所有要拼的字节数一次性加总,再调一次
reserve() - 例如拼接 1000 次
"abc",应写result.reserve(3 * 1000),而非在循环里反复调用 - 若子串来自
std::vector<std::string_view>,先遍历求和:std::accumulate(..., [](size_t s, auto& sv) { return s + sv.size(); }) - 留 5–10% 余量更稳妥,避免因内存对齐或 padding 触发最后一次扩容
单字符重复直接用构造函数,别走循环
std::string(count, ch) 是唯一无需 reserve() 的重复方式,底层调用 memset,零迭代、零检查。
- 写
for循环append(1, ch)不仅慢 10 倍以上,还容易误写成append('x')导致编译失败 - 不要用
+= 'x'循环——它等价于append(1, ch),但语义模糊,且某些 STL 实现对append有特化路径 - 若需混合字符(如生成带前缀的填充串),先构造单字符串再
append(),比逐字符拼更可控
多字符重复时避免 substr() 隐式拷贝
result.append(s.substr(0, 3), 4) 看似简洁,但 substr() 先分配新堆内存拷贝 3 字节,再追加 4 次——白费一次分配。
立即学习“C++免费学习笔记(深入)”;
- 尤其当
s很大而只取前几字节时,浪费更明显 - 正确做法是
result.append(s, 0, 3),直接从原字符串偏移处读取,零额外分配 - 若源是
std::string_view,直接result.append(sv),完全零拷贝;+= sv在老版 libstdc++ 中可能隐式转成std::string - 注意:
append(s, pos, len)要求pos + len ,否则崩溃;<code>substr()会截断但代价高
reserve() 后 size() 仍是 0,内容得手动写入
reserve() 只改变 capacity(),不改变 size(),也不初始化内存。你得用 append()、+= 或 operator[] 写入内容,不能指望 reserve 自动填满字符串。
- 误用
resize()替代reserve()是高频错误:s.resize(1000)会让字符串长度变成 1000,填充'\0',后续拼接会从索引 1000 开始写,导致中间出现大量空字符 - 若追求极致性能且格式高度规律(如日志行、协议头),可用
resize(total_len)+std::memcpy直接填充:std::memcpy(&result[0], data_ptr, len) -
reserve(0)合法但多数实现不释放内存;需真正收缩请用shrink_to_fit()
最容易被忽略的是:小字符串(reserve 反而更快;但一旦超出栈缓冲,性能断崖就来了——而这个阈值因编译器和标准库而异,没法靠经验猜。


















