C++ std::map用function作比较器触发bad_function_call异常问题
问题解答
这不是C++的设计问题,完全是符合语言和标准库规则的预期行为,对应疑问逐一说明:
为什么编译阶段不会报错?
- 首先
std::map的第三个模板参数只要求类型满足可调用规则:即该类型的对象可以被()调用,接受两个和key类型匹配的参数,返回值能转成bool。std::function<bool(int,int)>本身完全符合这个类型要求,模板类型检查阶段找不到任何报错的理由。 - 至于这个类型的对象是不是真的绑定了有效调用逻辑,属于运行时状态,编译器没法在编译阶段完全排查。就像你定义一个指针没给它赋有效值就解引用,编译器最多给个警告,不可能100%拦住所有这类问题,这类运行时状态合法性本来就是用户代码需要保证的。
- 你声明
m的时候没有给构造函数传比较器实例,map会对比较器类型做值初始化,对于std::function来说,值初始化出来的就是个没绑定任何调用目标的空对象,这个过程在语法上完全合法。
运行时抛异常的原因
std::map做插入、查找、遍历这类需要判断key顺序的操作时,一定会调用内部存储的比较器对象。而C++标准明确规定,调用空的std::function对象,必须抛出std::bad_function_call异常,这就是你看到报错的直接来源。- 之前遇到纯虚函数调用报同类错,本质都是「调用了不存在的有效实现」,和多态逻辑没有绑定关系,
std::function空态调用属于另一类触发场景。
C++标准的相关规定
- 对于
std::map这类有序关联容器,标准明确要求用户传入的比较器对象必须是满足严格弱序规则的有效可调用对象,这是使用容器的前置契约,标准库本身不强制检查这个契约是否满足。举个例子,如果你不用std::function,直接用函数指针类型当比较器,又没传有效函数地址,调用空函数指针会直接触发未定义行为,大概率直接段错误,连异常都不会抛。你这里能拿到明确的异常,反而是std::function做了空态检查的结果。 - 对于
std::function的调用行为,标准明确规定:当std::function实例未持有有效调用目标时,调用其operator()必须抛出std::bad_function_call类型的异常。
正确用法示例:构造map时传入合法的比较逻辑即可正常运行
std::map<int, int, std::function<bool(int, int)>> m([](int a, int b) { return a < b; });
内容的提问来源于stack exchange,提问作者Troskyvs
相关产品推荐
相关产品推荐

