3

max3ref

#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
}

$ g++ -o t2 t2.cpp
t2.cpp: In instantiation of ‘const T& max(const T&, const T&, const T&) [with T = const char*]’:
t2.cpp:30:29:   required from here
t2.cpp:20:26: warning: returning reference to temporary [-Wreturn-local-addr]
   return max (max(a,b), c);       
                          ^

Observation> The book says that the first statement(i.e. max(7, 42, 68) works because those temporaries are created in main() where they persist until the statement is done. However, I still have problems to understand why the first three-parameter max works while the second one failed.

Here are some experiments I have done and assume the following two functions are equivalent to two cases.

template<typename T>
T const& max (T const& a, T const& b, T const& c)
{
  printf("%s\n", __PRETTY_FUNCTION__ );
  const int& ab  = max(a, b);
  printf("address ab: %p\n", ab);
  const int& abc = max(ab, c);
  printf("address abc: %p\n", abc);

  return abc;
}

output:
with T = int
version 1
address ab: 0x2
version 1
address abc: 0x3

template<typename T>
T const& max (T const& a, T const& b, T const& c)
{
  printf("%s\n", __PRETTY_FUNCTION__ );
  const char* ab  = max(a, b);
  printf("address ab: %p\n", ab);
  const char* abc = max(ab, c);
  printf("address abc: %p\n", abc);

  throw 1; // throw here so that the compiler will be happy.
}

output:
with T = const char*
address s1: 0x4008da
address s2: 0x4008f3
address s3: 0x400909
version 2
address ab: 0x4008da
version 2
address abc: 0x400909

Question> I knew that you should not return a reference to a local variable defined within a function because that variable will not exist after the return of the function. Why the temporary variables in the first case were created in main function while the second case is defined within the function.

q0987
  • 34,938
  • 69
  • 242
  • 387
  • Make m2 const and it will compile. – Oblivion Oct 11 '19 at 15:39
  • 3
    You could change `max` with `char const*` to use `char const* &` (for both arguments and the return type) so that you always use references everywhere. – François Andrieux Oct 11 '19 at 15:39
  • 1
    You are aware that const & extends the lifetime of temporary to the scope of its definition? – Oblivion Oct 11 '19 at 15:40
  • 2
    @Oblivion That doesn't apply here. See [Does a const reference class member prolong the life of a temporary?](https://stackoverflow.com/questions/2784262/does-a-const-reference-class-member-prolong-the-life-of-a-temporary). – François Andrieux Oct 11 '19 at 15:40
  • @FrançoisAndrieux I know , but I believe it is worth noting when dealt with const & – Oblivion Oct 11 '19 at 15:41
  • @FrançoisAndrieux Surely you mean `char const &`. – Paul Sanders Oct 11 '19 at 19:23
  • @PaulSanders Well, no. The goal here is to call `std::strcmp` to compare the values of the pointed strings. – François Andrieux Oct 11 '19 at 19:24
  • 1
    Possible duplicate of [Why max (max(a,b), c) is error](https://stackoverflow.com/questions/14989564/why-max-maxa-b-c-is-error) – danadam Oct 11 '19 at 19:54
  • @FrançoisAndrieux You can do that via `strcmp(&a, &b)` if you pass `char const &`. – Paul Sanders Oct 11 '19 at 20:54
  • @PaulSanders But then `max('a','b');` will explode. `const char &` should be used to denote individual `char`s not strings. – François Andrieux Oct 12 '19 at 02:53
  • @FrançoisAndrieux Won't that be covered by `template T const& max (T const& a, T const& b)`? See: https://wandbox.org/permlink/PN7QjGio22fTGiKQ – Paul Sanders Oct 12 '19 at 17:46
  • @PaulSanders Not if you provide a `max(char const&, char const&);` overload as I understand you suggest. – François Andrieux Oct 12 '19 at 18:10
  • @FrançoisAndrieux Well, it seems to work, check out the link I provided. – Paul Sanders Oct 12 '19 at 18:11
  • @PaulSanders That's calling `strcmp` on pointers to `'a'` and `'b'` which is undefined behavior. In fact, it does not work. It only appears to work, probably because wherever those temporaries are stored happen to have a zero byte afterwards. When I tried running it on my system it returned `'b'` but if I swapped the arguments it returned `'a'`. Compiling does not mean working. – François Andrieux Oct 12 '19 at 18:15
  • @FrançoisAndrieux You're right, see: https://wandbox.org/permlink/rJPd6zxRNNLZJwmS – Paul Sanders Oct 12 '19 at 18:22

0 Answers0