You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

字符串自追加时反向迭代器的有效性保障问题

C++字符串拼接代码的有效性解答

问题描述

我需要生成一个由原字符串与其反转字符串拼接而成的新字符串,请问以下代码是否能保证正常运行?

auto pq = [](std::string &s){ s.reserve(2*s.size()); s.append(s.rbegin(), s.rend()); };

已知reserve会合理设置capacity,但调用append时使用反向迭代器,是否会导致这些迭代器失效?

参考标准条款

我的C11标准副本(与C17草案语言表述一致)中,§[string.capacity]节规定:

void reserve(size_type res_arg=0);
10. 成员函数reserve()是一条指令,告知basic_string对象计划进行的大小变更,以便其相应地管理存储分配。
11. 效果:调用reserve()后,capacity()将大于或等于reserve的参数。[注:调用reserve()时传入小于当前capacity()的res_arg参数,实际上是一个非强制性的收缩请求;传入res_arg <= size()的参数,则是一个非强制性的收缩至合适大小的请求。——结束注]
12. 抛出异常:若res_arg > max_size(),则抛出length_error异常。227


227) reserve()会使用allocator_traits::allocate(),该函数可能抛出相应的异常。

而§[string.append]节规定:

basic_string& append(const charT* s, size_type n);
11. 要求:s指向一个至少包含n个charT元素的数组。
12. 抛出异常:若size() + n > max_size(),则抛出length_error异常。
13. 效果:函数将this所控制的字符串替换为一个长度为size() + n的字符串,其前size()个元素是原this所控制字符串的副本,剩余元素是s的前n个元素的副本。
14. 返回值:*this。

解答

放心,这段代码完全可以保证正常运行,不会出现迭代器失效的问题,原因很明确:

首先,s.reserve(2*s.size())提前为字符串预留了足够的存储空间——调用后字符串的capacity()至少是原长度的两倍,而此时size()还是原字符串的长度。这意味着后续的append操作不需要扩容,因为总长度(原长度+反转后的长度)刚好等于2*s.size(),完全在预留的容量范围内。

那反向迭代器为什么不会失效?迭代器失效最常见的原因是容器发生内存重新分配(比如扩容时需要把旧内存的内容拷贝到新内存,旧迭代器就指向无效地址了),但这里我们已经提前搞定了容量,append过程中不会触发任何内存重新分配。而且,s.rbegin()和s.rend()指向的是原字符串的元素范围——append是在原字符串的末尾追加内容,原字符串的前半部分会被完整保留,这些元素的内存位置根本没动,反向迭代器指向的原字符串末尾到开头的位置自然也不会失效。

结合你贴的标准条款再确认下:

  • reserve的效果保证了容量足够,所以append不会触发扩容,避免了迭代器失效的核心诱因。
  • append的效果明确说明会保留原字符串的前size()个元素,再追加新内容,原元素的内存位置稳定,反向迭代器的指向一直有效。

举个实际例子:假设原字符串是"hello",reserve(10)后容量至少是10,size()还是5。调用append(s.rbegin(), s.rend())后,会把"olleh"追加到后面,最终得到"helloolleh"——整个过程中"hello"的内存位置没变化,反向迭代器指向的o、l、l、e、h也都在原来的位置,完全没问题。

内容的提问来源于stack exchange,提问作者jxh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:07:35