-2

I encountered the following error while trying to use C++ reference with objects. After reference to this question, I understood that it's because A() returns a temp variable, which is, by design, not allowed to be referenced to by a non-const reference. However, I'm still curious about why C++ is designed in that way. Why couldn't A& ra2 = A(); serve as a shorthand for A a1 = A(); A& ra1 = a1;? MSVC is known to support this kind of syntax by an extension, which nonetheless is not included in other implementations. Is there a particular downside of this shorthand?

class A {
    public:
        int a = 0;
};

int main()
{
    A a1 = A();
    A& ra1 = a1;  //okay
    A& ra2 = A(); //error: invalid initialization of non-const reference of type ‘A&’ from an rvalue of type ‘A’
    return 0;
}
Community
  • 1
  • 1
qweruiop
  • 3,156
  • 6
  • 31
  • 55
  • https://duckduckgo.com/?q=error%3A+invalid+initialization+of+non-const+reference+of+type+%E2%80%98A%26%E2%80%99+from+an+rvalue+of+type+%E2%80%98A%E2%80%99 -- you are supposed to do some research first. – Ulrich Eckhardt Aug 04 '15 at 04:49
  • @UlrichEckhardt I think I know what the error message means and why it happens. I'm not asking how to write correct code, rather my question is more about what's the semantic difference here. Because `ra1` and `ra2` have essentially the same net effect, semantically. So what's the point for C++ to disallow the second way of initialization? – qweruiop Aug 04 '15 at 05:08
  • @bl4ck5un so . . . you want a "[do what I mean](http://www.catb.org/esr/jargon/html/D/DWIM.html)" compiler? – geometrian Aug 04 '15 at 05:20
  • @imallett I'm talking about the design of C++ as a programming language. – qweruiop Aug 04 '15 at 05:23
  • @bl4ck5un as all the answers thus far have said, the two lines mean _very_ different things (and only one of them makes sense). It isn't actively _disallowed_ because C++ was designed to be restrictive; it _isn't implemented_ because it's not something that even makes sense to ask for. – geometrian Aug 04 '15 at 05:27
  • It does make sense to ask for it. It's just disallowed anyway. – M.M Aug 04 '15 at 05:29
  • @MattMcNabb making a reference to a constant only makes sense if you _expect_ a constant to be allocated with (edit: _designed-for-supporting_) move semantics. There's a completely different (`&&`) syntax for that because it's a completely different thing. – geometrian Aug 04 '15 at 05:34
  • 1
    This has nothing to do with move semantics. "allocated with move sematics" don't even make sense. – M.M Aug 04 '15 at 05:35
  • @MattMcNabb [move semantics](https://msdn.microsoft.com/en-us/library/dd293668.aspx?f=255&MSPPError=-2147217396) – geometrian Aug 04 '15 at 05:37
  • @imallett I know what move semantics are, and they are unrelated to this question. You seem to be mentally equating rvalue references with move semantics. – M.M Aug 04 '15 at 05:40
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/85059/discussion-between-imallett-and-matt-mcnabb). – geometrian Aug 04 '15 at 05:40
  • @MattMcNabb Anyway, at least I __don't__ think it's a duplicated question. Maybe SO isn't the perfect place to discuss this, but my question is by far different from the one you guys pointed to. – qweruiop Aug 04 '15 at 05:42
  • @bl4ck5un perhaps you could edit your question to make it clearer exactly what you are asking. `ra2` is *illegal code* therefore it does not have the same semantic effect as anything. Are you proposing a behaviour for the ra2 line? If so, specify that behaviour. – M.M Aug 04 '15 at 05:46
  • " I understood that it's because A() returns a temp variable, which is const" - no, it is not `const`. You may modify it, e.g. `A().x = 5;` – M.M Aug 04 '15 at 06:23
  • Maybe [this answer](http://stackoverflow.com/a/13827243/1505939) would also be useful to read. I have a recollection of Bjarne saying that in hindsight he would have allowed this binding. – M.M Aug 04 '15 at 06:27
  • @MattMcNabb Thank you Matt. – qweruiop Aug 04 '15 at 18:41

3 Answers3

1

In the line

A& ra2 = A(); 

The right hand side of the = operator evaluates to a temporary object. You can only use a const& to reference a temporary object.

The line

A& ra1 = a1;  //okay

works since a1 is not a temporary object and it is not a const object either.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Please see my update of question. – qweruiop Aug 04 '15 at 05:15
  • @bl4ck5un, It's not clear to me why you think a reference to `a1` and a refernce to `A()` is semantically same. You have some idea of what it means to you but that idea is not clear to me. – R Sahu Aug 04 '15 at 05:22
  • @R Sahu First of all, let's forget the current C++ spec for a moment and consider possible improvement to C++. That being said, by `ra2`, I clearly intend to refer to an object of `A()`, rather than a temp variable because it makes no sense. So the question is, why C++ is _not_ designed in the way I just explained. I believe there is some good reasons (something rooted at Theory of PL) , then what's that? – qweruiop Aug 04 '15 at 05:36
  • @bl4ck5un, I am afraid I don't know the evolution of C++ to such depth. – R Sahu Aug 04 '15 at 05:38
  • @bl4ck5un *It does make sense* . You request a temp object, you get a temp object. (Technically temporaries are not variables). If you don't want a temp object don't write `A()` . `A()` clearly specifies that you want a temporary . – M.M Aug 04 '15 at 05:39
  • @MattMcNabb Okay, fair enough. – qweruiop Aug 04 '15 at 05:48
0
A& ra2 = A();

ra2 is trying to refer to a temporary variable. And it wouldn't make any sense to change that temporary variable. So, compiler prohibits you from doing any non-sense.

ravi
  • 10,994
  • 1
  • 18
  • 36
  • It does make some sense, as evinced by the fact that they later added `A&& ra2 = A();` – M.M Aug 04 '15 at 05:08
  • I agree that it makes no sense to change a temp variable. Why doesn't compiler just compile `A& ra2 = A();` to the first way of initialization. Does it hurt anything? – qweruiop Aug 04 '15 at 05:19
  • @MattMcNabb I mean is there a particular reason why isn't compilers doing that optimization? – qweruiop Aug 04 '15 at 05:26
  • MSVC used to have such an extension. I wouldn't call it an optimization – M.M Aug 04 '15 at 05:27
-2

Think of a reference as a fancy pointer with compile-time checks and potentially less overhead.

A& ra2 = A();

This says:

  1. Make me a temporary object of type A.
  2. Destroy that temporary object.
  3. Make a "pointer" to that temporary-object-that-doesn't-exist.

This is where the checking enters in. The compiler realizes this doesn't make sense, and is telling you so.

You're probably confused by the similar syntax:

A my_a = A();

However, this example is critically different. It says:

  1. Make me a temporary object of type A.
  2. Copy that temporary object into my_a (call my_a's copy constructor)
  3. Delete the temporary object
geometrian
  • 14,775
  • 10
  • 56
  • 132
  • Sorry, but if the code was adjusted to use `const`, it changes the outcome, but your answer doesn't explain that *at* *all*. – Ulrich Eckhardt Aug 04 '15 at 04:55
  • @UlrichEckhardt const references to temporaries are a wart that breaks the intuitive syntax I described above--and SO is also about teaching best practices as well as facts. Since the OP was not asking about why a _const_ reference would have compiled (and since s?he is obviously a neophyte), I didn't mention it.¶ However, as in your comment above, this is clearly a duplicate, and I probably shouldn't have bothered answering it. [This](http://stackoverflow.com/a/8293453/688624) answer is better. – geometrian Aug 04 '15 at 05:06
  • Your first 1,2,3 are completely wrong – M.M Aug 04 '15 at 05:09
  • @MattMcNabb Since it's invalid C++ to begin with, I imagine that's self-evident. However, I would welcome your clarification if you'd offer it. – geometrian Aug 04 '15 at 05:18
  • @imallett yes it's invalid C++ so there is no temporary made or destroyed. There is no basis for saying that if this code were legal, the temporary would not have its lifetime extended. The reason (if there even is one) that this code is not legal, is not because it would make a dangling reference, because it wouldn't. If this code had been permitted then I feel pretty confident to say that it would have been specified to extend the temporary's lifetime. Certainly `A&& ra2 = A();` does extend. – M.M Aug 04 '15 at 05:26
  • @MattMcNabb an rvalue reference is _very_ different from an lvalue reference, which this is. A `const` reference will also extend the lifetime. I consider the latter a wart stopgapping for the former, and the former advanced. In any case, I feel like my semantic description accurately reflects the reason the syntax is disallowed. – geometrian Aug 04 '15 at 05:32
  • @imallett all references are the same once they are bound. The only difference between non-const lvalue refs and rvalue refs is that rvalue refs can bind to an rvalue. It seems to me you've just invented all of this "rationale". – M.M Aug 04 '15 at 05:34
  • @MattMcNabb I acknowledge the possibility that I may be mistaken--and I originally asked for clarification in case I was. However, I don't see an incompatibility with what either of us are saying. – geometrian Aug 04 '15 at 05:36