C++中memmove_s函数异常处理相关报错的解决方案咨询
问题根因说明
memmove_s属于C标准安全函数,参数校验失败时默认触发的是结构化异常(SEH),不是C++标准异常,所以普通try/catch无法捕获。- 报错
Cannot use __try in functions that require object unwinding是因为微软SEH的__try/__except块默认不支持和包含RAII对象(你的函数里有std::string类型参数,退出时需要调用析构函数做对象自动清理)的函数混用,编译器不允许该写法。 - 你代码中
memmove_s传参destSize + 1是错误逻辑,destSize本身就应该是目标缓冲区的总可用大小,加1会导致越界校验失效,反而会引入安全风险。
可行解决方案
方案1:禁用安全函数异常触发,判断返回值处理(最推荐)
memmove_s本身会通过返回值标识错误状态,不需要依赖异常处理,你只需要关闭CRT默认的异常触发逻辑即可:
- 全局自定义无效参数处理函数,避免CRT自动抛异常:
#include <stdlib.h> #include <crtdbg.h> // 全局设置仅需调用一次 void my_invalid_param_handler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t reserved) { // 可按需加错误日志,不需要抛异常 } // 程序初始化阶段执行一次 _set_invalid_parameter_handler(my_invalid_param_handler); _CrtSetReportMode(_CRT_ASSERT, 0); // 关闭CRT断言弹窗
- 直接判断
memmove_s返回值处理错误,不需要任何异常捕获逻辑:
extern "C" void get_str_value(string src, char* dest, unsigned int destSize) { errno_t r = memmove_s((void*)dest, destSize, src.c_str(), src.size() + 1); if (r == 0) { cout << "拷贝成功,r=" << r << endl; } else if (r == ERANGE) { cout << "目标缓冲区大小不足,拷贝失败" << endl; // 按需加错误处理逻辑 } else { cout << "其他错误,错误码:" << r << endl; } }
方案2:抽离SEH逻辑到无RAII对象的独立函数
如果必须用__try/__except捕获异常,把拷贝逻辑抽离到没有需要自动析构的C++对象的纯C风格函数中即可:
// 内层纯C风格函数,无RAII对象,支持__try/__except extern "C" int safe_memmove(void* dest, size_t destSize, const void* src, size_t srcSize) { __try { return memmove_s(dest, destSize, src, srcSize); } __except (filter(GetExceptionCode(), GetExceptionInformation())) { std::cout << "捕获到SEH异常" << std::endl; return -1; } } // 外层函数处理RAII对象,不需要加__try extern "C" void get_str_value(string src, char* dest, unsigned int destSize) { int r = safe_memmove(dest, destSize, src.c_str(), src.size() + 1); cout << "r=" << r << endl; }
方案3:开启/EHa编译选项(不推荐)
在Visual Studio项目属性中,找到C/C++ -> 代码生成 -> 启用C++异常,选择是,但有 SEH 异常 (/EHa),开启后普通C++ try/catch(...)就可以捕获SEH异常,不需要改业务代码。但该选项会修改C++异常的默认处理逻辑,可能会把内存访问越界等致命异常也捕获,引入隐性风险,非必要不建议使用。
内容的提问来源于stack exchange,提问作者Thiago Cavalcante
相关产品推荐
相关产品推荐

