我正在阅读Vandevoorde,Josuttis和Gregor撰写的有关C++模板的书,但不理解它们对悬挂引用提出的警告。
这是代码:
#include <cstring>
// maximum of two values of any type (call-by-reference)
template<typename T>
T const& max (T const& a, T const& b)
{
return b < a ? a : b;
}
// maximum of two C-strings (call-by-value)
char const* max (char const* a, char const* b)
{
return std::strcmp(b,a) < 0 ? a : b;
}
// maximum of three values of any type (call-by-reference)
template<typename T>
T const& max (T const& a, T const& b, T const& c)
{
return max (max(a,b), c); // error if max(a,b) uses call-by-value
}
int main ()
{
auto m1 = ::max(7, 42, 68); // OK
char const* s1 = "frederic";
char const* s2 = "anica";
char const* s3 = "lucas";
auto m2 = ::max(s1, s2, s3); // run-time ERROR
}
给定的消息是,对于C字符串,嵌套的
max(a,b)
创建了一个悬空引用,而对于int,则没有。那么,与char相比,与int的引用相比,char的特殊之处是什么呢(假设两者均实现为指向
max
函数外部分配的对象的指针)? 最佳答案
::max(s1, s2, s3)
使用template<typename T> T const& max (T const& a, T const& b, T const& c)
返回引用
如果template<typename T> T const& max (T const& a, T const& b, T const& c)
的定义更改为:
template<typename T>
T const& max (T const& a, T const& b, T const& c)
{
return (a > b) ? ((a > c) ? a : c)
: ((b > c) ? b : c);
}
没问题,因为它已经有了引用。
但是对于
::max(s1, s2, s3)
,T是const char*
,因此在max (max(a,b), c)
中,最大的是char const* max (char const* a, char const* b)
,它不返回引用,因为编译器将char const* max (char const* a, char const* b)
的结果保存在堆栈中的临时变量中,并返回对该临时变量的引用,从而生成消息并生成相关问题。就像您执行int & f() { int v = 0; return v; }
一样,只是临时变量是由编译器本身创建的。当然,使用
template<typename T> T const max (T const& a, T const& b, T const& c)
(返回值而不是引用)后,问题就消失了,因为可以直接返回char const* max (char const* a, char const* b)
返回的值。注意
::max(7, 42, 68)
没问题,因为max (max(a,b), c)
中的max是template<typename T> T const& max (T const& a, T const& b)
,它返回一个引用。在其他情况下,要继续返回引用,您可以将max专门用于
char *
,例如:// maximum of two C-strings (call-by-value)
template<>
char const* const & max (char const* const & a, char const* const & b)
{
return std::strcmp(b,a) < 0 ? a : b;
}
或定义为
char const* const & max (char const* const & a, char const* const & b)
{
return std::strcmp(b,a) < 0 ? a : b;
}
其返回引用的版本可以使用具有三个参数的版本,而不必使用临时变量并返回对其的引用。
(我个人更喜欢特化,因为拥有模板版本看起来很自然)
#include <cstring>
#include <iostream>
// maximum of two values of any type (call-by-reference)
template<typename T>
T const& max (T const& a, T const& b)
{
return b < a ? a : b;
}
// MODIFIED
// maximum of two C-strings (call-by-value)
template<>
char const* const & max (char const* const & a, char const* const & b)
{
return std::strcmp(b,a) < 0 ? a : b;
}
// maximum of three values of any type (call-by-reference)
template<typename T>
T const& max (T const& a, T const& b, T const& c)
{
return max (max(a,b), c); // error if max(a,b) uses call-by-value
}
int main ()
{
auto m1 = ::max(7, 42, 68); // OK
char const* s1 = "frederic";
char const* s2 = "anica";
char const* s3 = "lucas";
auto m2 = ::max(s1, s2, s3); // run-time ERROR
std::cout << m2 << std::endl; // << ADDED TO CHECK
}
编译与执行:
pi@raspberrypi:/tmp $ g++ -pedantic -Wall -Wextra s.cc
s.cc: In function ‘int main()’:
s.cc:28:8: warning: unused variable ‘m1’ [-Wunused-variable]
auto m1 = ::max(7, 42, 68); // OK
^~
pi@raspberrypi:/tmp $ ./a.out
lucas
关于c++ - 悬空指针/对int和char *常量的引用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55797433/