C++重载针对C字符串的函数模板时运行错误原因求解
以下代码片段取自《C++ Templates》一书的示例,三参数max函数模板最后一行的
return max(max(a,b), c)语句在传入C字符串参数时会触发运行时错误,对应的代码如下:
#include <cstring> // 任意类型两个值的最大值(按引用传递) template<typename T> T const& max (T const& a, T const& b) { return b < a ? a : b; } // 两个C字符串的最大值(按值传递) char const* max (char const* a, char const* b) { return std::strcmp(b,a) < 0 ? a : b; } // 任意类型三个值的最大值(按引用传递) template<typename T> T const& max (T const& a, T const& b, T const& c) { return max (max(a,b), c); // 当max(a,b)按值返回时会出错 } int main () { auto m1 = ::max(7, 42, 68); // 运行正常 char const* s1 = "frederic"; char const* s2 = "anica"; char const* s3 = "lucas"; auto m2 = ::max(s1, s2, s3); // 运行时错误 }
问题原因分析
核心触发点是返回了悬空引用,属于C++中的未定义行为,具体逻辑拆解:
- 当传入
char const*类型参数调用三参数max模板时,模板参数T会被推导为char const*,因此三参数max的返回类型为T const&,也就是char const* const&,本质是指向C字符串指针的常量引用。 - 三参数
max内部调用两参数max处理C字符串时,重载决议会优先匹配非模板的char const* max(char const* a, char const* b)版本,该版本是传值返回,执行完会生成一个临时的char const*指针对象。 - 内层
max(a,b)返回的临时指针会作为参数传入外层的两参数max调用,最终外层max返回的也是临时指针对象,三参数max会把这个临时对象绑定到要返回的引用上。 - 三参数
max执行结束后,返回的临时指针对象会被销毁,返回的引用就变成了悬空引用,后续访问m2时就会触发运行时错误。
可行修复方案
- 方案1:调整C字符串版本两参数
max的返回类型为引用,避免返回临时对象:
char const* const& max (char const* a, char const* b) { return std::strcmp(b,a) < 0 ? a : b; }
- 方案2:修改三参数
max的返回类型为传值,避免引用绑定到临时对象:
template<typename T> T max (T const& a, T const& b, T const& c) { return max (max(a,b), c); }
- 方案3:调用三参数
max时显式指定模板参数,强制使用模板版本的两参数max,避免匹配到C字符串的传值重载:
auto m2 = ::max<char const*>(s1, s2, s3);
内容的提问来源于stack exchange,提问作者Willi
相关产品推荐
相关产品推荐

