非法输入漏检源于契约未写死、边界未卡严、测试未打穿;函数参数必须有明确输入约束,前置条件须用assert等可执行机制落实,如array::at需强制检查index

直接测,别绕弯——封装接口的非法输入漏检,本质是契约没写死、边界没卡严、测试没打穿。只要函数对外暴露了参数,就一定得有明确的输入约束,否则调用方迟早踩坑。
用 assert 或契约宏守住前置条件
前置条件不是文档里的一句话,得落到代码里可执行、可触发。比如一个封装的 Array::at(size_t index) 接口,不能只靠注释说“index 必须小于 size”,而要强制检查:
assert(index —— 调试版立即崩,比静默越界更早暴露问题- 若用契约编程(如自定义
ENSURE/REQUIRE宏),把index 写进函数头,和函数签名一样不可省略 - 注意:发布版若定义了
NDEBUG,assert会消失,所以关键校验不能只依赖它;对生产环境必须生效的检查,得用显式if+ 抛异常或返回错误码
单元测试必须覆盖“错得离谱”的输入组合
合法输入测通不算过关,真正检验封装质量的是那些明摆着不该进来的值。比如一个接受 std::string 的解析接口:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 空字符串:
""—— 是允许?还是应报错?接口契约里必须明确 - 含控制字符的字符串:
"\x00\x01"—— 是否导致后续c_str()截断或解析崩溃? - 超长字符串(远超预期长度)—— 是否引发分配失败、缓冲区溢出或无限循环?
- 非 UTF-8 编码字节序列(如
"\xff\xfe")—— 若接口声称支持 UTF-8,就得验证解码失败路径是否被正确捕获
用 std::any_cast 类型擦除场景要额外防“空值+错类型”双重失效
如果封装接口内部用了 std::any 做泛型传递(比如配置项存储),最容易漏掉两类非法态:
-
std::any对象本身没值:data.has_value() == false,但直接std::any_cast<int>(data)</int>会抛std::bad_any_cast - 值存在但类型不匹配:
data存的是double,却用int&去取 —— 引用版any_cast一定炸,指针版返回nullptr,但很多封装层忘了判空 - 正确姿势:先
if (data.has_value() && data.type() == typeid(int)),再用指针版std::any_cast<int>(&data)</int>安全取值
文件/网络等外部输入接口,非法不只是格式,更是状态
比如封装了一个 ConfigLoader::load(const std::string& path),常见漏检点不在 JSON 语法错,而在这些“合法字符串但非法上下文”:
- 路径是相对路径且当前工作目录已切换 ——
"./config.json"实际打不开 - 文件存在但权限不足(
open() returns -1, errno == EACCES) - 文件被其他进程独占锁定(Windows 上常见)
- 路径指向符号链接循环(
readlink深度超限) - 对应测试必须在真实文件系统上跑,不能只 mock
std::ifstream::is_open()返回 true
最常被跳过的其实是“输入虽合法但语义非法”的情况:比如时间戳是有效数字,却是负数;枚举值是合法整数,却不在预定义范围内。这类问题不会让程序当场崩溃,但会让业务逻辑悄悄走偏——它们得靠契约 + 显式校验 + 针对性测试用例三者卡死。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










