悬挂 pointers/references 到 int 和 char* 常量

Dangling pointers/references to int and char* constants

我正在阅读 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 则不会。 那么,与对 int 的引用相比,指向 char 的指针有何特别之处,因为两者都是作为指向在 max 函数外部分配的对象的指针实现的?

... do not understand the warning they make about dangling reference

::max(s1, s2, s3) 使用 template<typename T> T const& max (T const& a, T const& b, T const& c) returning a reference

如果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) Tconst char* 所以 max (max(a,b), c) maxchar const* max (char const* a, char const* b) 没有 return 引用,因此编译器将 char const* max (char const* a, char const* b) 的结果保存在堆栈上的一个临时变量中,并将 return 保存为该临时变量的引用,从而生成您的消息和相关问题。就像你做 int & f() { int v = 0; return v; } 除了临时变量是由编译器自己创建的。

当然问题消失了 template<typename T> T const max (T const& a, T const& b, T const& c)(returning 一个值而不是一个引用)因为 returned char const* max (char const* a, char const* b) 的值可以直接 returned.

注意 ::max(7, 42, 68) 没有问题,因为 max (max(a,b), c) 中的 maxtemplate<typename T> T const& max (T const& a, T const& b),return 是参考。

要继续 return 其他情况下的参考,您可以将 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;
}

其 return 具有三个参数的版本可以使用的引用,而无需使用临时变量和 return 对它的引用。

(我个人更喜欢专业化,因为有模板版本似乎很自然)


#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

这个:

   char const* max (char const* a, char const* b)

returns 一个无名的临时指针值,然后是:

    return max (max(a,b), c);

returns 对其的引用。