1

I was experimenting with Universal references inspired by Scott Meyers article on the subject.

So I tried the following:

#include <iostream>
#include <cassert>

template<typename T>
T& f(T&& var){
    std::cout<< &var << std::endl;
    return var;
}

int main() {
    int& j = f(10);
    std::cout<< &j << ", " << j << std::endl;
    int& k = f(20);
    std::cout<< &k << ", " << k << std::endl;

    if( &j == &k ){
        std::cout<< "This is peculiar." <<std::endl;
    }

    return 0;
}

With the output:

0x7ffff8b957ac
0x7ffff8b957ac, 10
0x7ffff8b957ac
0x7ffff8b957ac, 20
This is peculiar.

I was under the impression that &j == &k would guarantee that j==k.

What is happening here?

Edit, post answer:

Anecdotal reflection: Outputting j instead of k in the second printout makes the program output nothing at all. I guess I should be happy there were no Chesterfield sofas or whales involved.

Captain Giraffe
  • 14,407
  • 6
  • 39
  • 67
  • 4
    Universal behavior. Sorry, I mean undefined behavior. – Kerrek SB Aug 12 '14 at 22:35
  • 1
    @CaptainGiraffe, [Can a local variable's memory be accessed outside its scope?](http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope) (Spoiler: The answer is no) – chris Aug 12 '14 at 22:37
  • As my wife always says, "dangling reference"... – Kerrek SB Aug 12 '14 at 22:37

1 Answers1

2

You are using references bound to temporary objects after the lifetimes of those temporary objects have ended. In most cases, a temporary only lives until the end of the statement or other full-expression; and this program doesn't have any of the exceptions that would extend its lifetime. Since the lifetimes of the objects don't overlap, the compiler is allowed to use the same address for both. And your cout statements, using those dead objects, are Undefined Behavior - anything could happen.

aschepler
  • 70,891
  • 9
  • 107
  • 161
  • Indeed. Perhaps I should have deduced this myself. I'm still struggling with my intuition on `T&&` stuff. Thanks. – Captain Giraffe Aug 12 '14 at 22:41
  • Well, you would have the same problems and probably the same results if all your reference types were `const int&`. Both kinds of references have the same interactions with lifetimes and temporaries, except that an lvalue reference without `const` won't bind to an rvalue at all. – aschepler Aug 12 '14 at 22:46