C++模板三值max函数处理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); // 运行时错误(未定义行为) }
疑惑解答
1. 为什么调用非模板max会生成临时值?
非模板版本的max(char const*, char const*)是按值返回的。函数内部返回的a或b是传入指针的副本——这个副本会作为临时对象被创建在调用栈上,用来承接函数的返回值。当这个临时值被传递给三参数模板max时,模板函数返回的是对该临时指针的引用。一旦return语句执行完成,这个临时指针就会被销毁,最终导致main函数中的m2持有一个指向已释放内存的悬垂引用。
2. 为什么VS2022测试时未出现错误?
这是未定义行为的典型表现:C++标准对悬垂引用的后果没有任何规定,程序可能正常运行、崩溃、输出错误结果,甚至在不同环境下表现完全不同。VS2022没报错的可能原因包括:
- 临时对象的内存空间尚未被其他数据覆盖,访问时恰好能读到正确值;
- 编译器优化(如O2/O3等级)将函数调用内联,消除了临时对象的创建;
- 未定义行为的触发具有随机性,本次测试刚好未触发可见错误,但代码本身依然存在严重问题。
内容的提问来源于stack exchange,提问作者Haswell
相关产品推荐
相关产品推荐

