std::string构造应避免隐式转换,推荐用花括号初始化;find返回npos而非-1,需显式比较;substr越界不抛异常但自动截断或返回空串。

std::string 构造和初始化时,别直接用 char* 字面量赋值给空 string
很多人写 std::string s = "hello" 看似没问题,但实际调用了 std::string(const char*) 构造函数,隐式转换容易掩盖空指针风险。如果传入的是可能为 nullptr 的 char*,程序会直接崩溃。
- 安全做法是显式检查:先判断指针是否非空,再构造;或用
std::string_view做中间层(C++17 起) - 初始化字符串常量推荐用花括号:
std::string s{"hello"},能禁用部分隐式转换 - 从 C 风格字符串复制时,
std::string s(p, len)比std::string s(p)更可控,避免越界读取
find / rfind 返回 std::string::npos,不是 -1,比较前必须用它而不是数字
std::string::find 找不到时返回 std::string::npos,其值是 size_t 类型的最大值(通常是 0xffffffffffffffff),不是 -1。拿它跟 -1 比较会导致无符号整数溢出,条件永远为假。
- 正确写法:
if (s.find("abc") != std::string::npos) - 错误写法:
if (s.find("abc") != -1)—— 编译器可能警告,运行时逻辑错 - 在 32 位环境或某些嵌入式 STL 实现中,
npos可能是0xffffffff,仍不等于-1(有符号)
substr 越界不会抛异常,但行为取决于起始位置和长度
substr 在超出范围时不会 crash,但结果可能不符合直觉:当起始位置超过字符串长度,返回空串;当长度超出剩余字符数,自动截断到末尾。
- 例如:
s = "ab",s.substr(3, 10)返回空串"",不是崩溃 - 而
s.substr(1, 10)返回"b",不是报错 - 如果你依赖“越界即失败”,得手动检查:
if (pos - 注意:
pos是size_t,和负数比较会触发隐式转换,慎用pos 这类判断
append / assign / replace 参数顺序易混淆,尤其涉及迭代器和数量
这几个函数重载多,参数含义随类型变化大。比如 append(n, c) 是追加 n 个字符 c;append(first, last) 是追加迭代器区间;append(str, pos, len) 是从 str 的 pos 开始取 len 个字符——三者参数结构完全不同。
- 最常踩坑:把
s.append(5, 'x')误写成s.append('x', 5),编译不过(参数类型不匹配) -
replace(pos, len, str)中的len是要被替换掉的长度,不是新字符串长度 - 用迭代器版本(如
replace(it1, it2, str))更直观,但要注意迭代器有效性,特别是操作过程中string可能重新分配内存 - 性能提示:连续多次
append建议先reserve,避免反复 realloc
真正麻烦的不是记不住所有重载,而是调试时发现逻辑分支走到了意料之外的重载上——尤其当变量类型是 auto 或模板推导结果模糊时,append 和 assign 的行为差异会悄悄改变语义。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










