68

Possible Duplicate:
Does a const reference prolong the life of a temporary?
prolonging the lifetime of temporaries

C++ allows assignment of temporary objects only to const reference. It wont allow assignement of temporary objects to reference.

For example:

String& a = String("test");         // Error
const String& a = String("test");   // Ok

Everywhere I google for this result, i only see the following answers

  1. Modifying temporary objects would cause unidentifiable problems
  2. Modifying temporary objects is dangerous
  3. At some point of time, you will forget it is a temporary variable

It's been said, temporary objects vanishes after the statement. So you should not modify it.

If C++, is so keen in blocking modifying the temporary objects, it should have blocked reading the temporary objects right? If the temporary object is vanished, then there is no point in reading contents from there right? The possible cases, where a right can occur, could also involve the read too.

Then why its been blocking write alone and allowing read?

Please give me a solid c++ code explanation.

Please dont deviate the question by pointing some alternatives. Please give me solid answer with code why const int & is allowed and int & is not allowed for temporary objects.

One says && is there.. My question different.. ANother say,changing will not reflect.. Changing will not reflect even when it is const int & too. Eg: double a; Const int & i = a; a++; will not affect i..

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
user738471
  • 879
  • 1
  • 8
  • 10
  • I'm not sure I understand the question. Does [this](http://stacked-crooked.com/view?id=49e766dcb26e7f773e3b497c2ff41a52) count as reading from a temporary? If you're talking about one that's passed to a function, you need to copy it, move it, or use a const reference, which extends its life. – chris Dec 11 '12 at 19:16
  • 3
    +1 I've wondered about this too. – user541686 Dec 11 '12 at 19:18
  • I think it's very hard to analyze all the references to an object for compiler writers to give any warranties. – Dmytro Sirenko Dec 11 '12 at 19:18
  • 1
    @EarlGray: Yup, so how is that different for const vs. non-const temps? – user541686 Dec 11 '12 at 19:23
  • See http://stackoverflow.com/questions/4084053/passing-non-const-references-to-rvalues-in-c and http://stackoverflow.com/questions/8293426/error-invalid-initialization-of-non-const-reference-of-type-int-from-an-rval . By the way, both forms work in VC++ 2012 – SomeWittyUsername Dec 11 '12 at 19:24
  • 1
    Because `C++` extends the lifetime of temporaries that are bound to `const references` on the stack. See the top answer here: http://stackoverflow.com/questions/2784262/does-a-const-reference-prolong-the-life-of-a-temporary – Chad Dec 11 '12 at 19:35
  • @Mehrdad A similar problem in C: http://en.wikipedia.org/wiki/Pointer_aliasing – Dmytro Sirenko Dec 11 '12 at 19:38

4 Answers4

40

The original case for not allowing references to temporaries was for function parameters. Suppose this was allowed:

void inc(double& x)
{ x += 0.1; }

int i = 0;
inc(i);

Why isn't i changed?

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • 2
    Couldn't this just error at compile time? (Doesn't it?) I'm not sure where the problem is... – user541686 Dec 11 '12 at 19:25
  • 15
    It does fail now, it wouldn't fail if binding to a temporary was allowed. The int is converted to a temp double before being passed to the function. – Bo Persson Dec 11 '12 at 19:27
  • 3
    Hmm, interesting... but couldn't they say "if the value is already an l-value reference, then no implicit conversions are allowed to another l-value reference type"? Or maybe that would defeat the point... not sure, still thinking about it... +1 – user541686 Dec 11 '12 at 19:28
  • in this case const double& and double are all same result. Tell me an exact example, where I can see the exact use of const reference and demerit of reference there – user738471 Dec 11 '12 at 19:32
  • 1
    This is a top-notch example, user738471. Change the `int i` to `double i` and there's no problem. Change the function to `do_something_with_const_double(const double& x)` and there's no problem with calling this new function with an `int` as an argument. – David Hammen Dec 11 '12 at 19:39
  • Consider this, const double &i = a; a++; will i value change? No right? then that also wont change. – user738471 Dec 12 '12 at 05:44
  • 1
    @user738471 Why wouldn't it change the value of i? its the same as 'int a = 0; const int* p = &a; ++a;' *p == 1, isn't it? – rozina Sep 11 '14 at 14:27
  • I think i should increment by 1 in this example, regardless of whether or not it actually does. A better example would perhaps be to increment x by 0.1, for clarification. – Andrew Jun 05 '15 at 04:38
  • 2
    @Andrew How does that clarify anything? `i` cannot be incremented because the function doesn't accept `int &`, only `double &`. So, from `i`, it gets a conversion-constructed temporary `double`, and that's what's changed. Magnitude of change is wholly irrelevant: `i` is out of the picture by the time the call is made. I'm actually glad C++ doesn't allow this due to all the questions we'd get otherwise: 'But I incremented by a whole number, so it should work then, right?' That sounds like what you're saying. But I might be missing something. – underscore_d Jul 06 '16 at 18:45
  • 1
    It clarifies things because in the previous example (edited over), I could actually see that working; that is, it would make sense. In the current example, however, it reminds the reader that we are in fact trying to change the value of a double rather than an int. Thus, by attempting to add 0.1, the reader will realize that you wouldn't want to do that to an int and they will be forced to understand the typing properly. – Andrew Jul 07 '16 at 19:31
  • 5
    This example rather demonstrates that allowing implicit conversions is not a good idea. – user7860670 Dec 16 '17 at 20:58
21

If C++, is so keen in blocking modifying the temporary objects, it should have blocked reading the temporary objects right? If the temporary object is vanished, then there is no point in reading contents from there right?

No, reading the object is perfectly sensible. Just because it's going to vanish in the future doesn't mean reading the data now is pointless.

open_file(std::string("foo.txt"));

std::string("foo.txt") is a temporary which will stop existing after the call to open_file() but the data it contains while it does exist matters very much.

The rationale for not allowing temporaries bind to non-const references isn't actually some fundamental problem with writing to temporaries. In fact in many places C++ is perfectly happy to allow temporaries to be modified:

std::string("foo") = "bar";

It's just that the designers felt that it would cause a sufficient number of problems (probably due to the common idiom of 'out parameters') without enabling anything of similar value, so they simply made a design decision to prohibit temporaries binding to non-const references.

With rvalue references now you can do exactly what was prohibited before:

void foo(int &&output) {
    output = 1;
}

foo(2);

This works fine, it's just not very useful.

Ofek Shilon
  • 14,734
  • 5
  • 67
  • 101
bames53
  • 86,085
  • 15
  • 179
  • 244
  • 12
    "The rational for not allowing temporaries bind to non-const references isn't actually some fundamental problem with writing to temporaries" - thanks for mentioning that. – zaptir Jul 23 '13 at 11:26
7

If you have a temporary object that's very expensive to copy, you may prefer to take a const& to that object (say a function return) rather than copying it into another variable to use later. Taking a constant reference to a temporary extends the life of that temporary to as long as the reference lives, allowing you to access any readable state.

Writing is disallowed because as soon as you want to mutate a variable you may as well have a real instance rather than a temporary that's aliased only as a non-const reference.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • 1
    "Taking a constant reference to a temporary extends the life of that temporary to as long as the reference lives"... what? That's only true if they're passing an actual object, not e.g. another const reference to it. And it doesn't explain why non-const references couldn't do the same. – user541686 Dec 11 '12 at 19:24
  • 1
    @Mehrdad the question seems to clearly state taking a const reference to an actual by-value temporary object. I may have misread the OP's intention though. – Mark B Dec 11 '12 at 19:25
  • 1
    "as soon as you want to mutate a variable you may as well have a real instance" precisely, +1 – underscore_d Jul 06 '16 at 18:44
1

There is a logical reason to this. Think, what actually you want in this line:

String& a = String("test");         // Error

You want a reference. A reference relates to the object it references to. Like an address of the object (although references are not addresses, it makes the explanation clearer this way). You actually try to get something like an address of String("test"). But that object will vanish right on the next line, so what's the point of its address, if the object it points to doesn't exist? a now points to something meaningless...

Regarding your second question, what's the point of allowing for temporary objects alltogether, well, there is nothing wrong with that. Consider for example, the case where you want to pass a String object to a function, which returns, say, a modified string corresponding to that String. Let's call the function DoubleString, so instead of doing

String s("hello ");
String s2 = DoubleString(s);

You can use a shorter, more convenient form

String s2 = DoubleString(String("hello "));

See, the temporary object String("hello ") survives the entire line of code, which means it is intact when sent to DoubleString and after it. It is destroyed only when the entire line has finished.

Israel Unterman
  • 13,158
  • 4
  • 28
  • 35
  • 2
    The first example is not relevant. You can make it a `const String& a = ...` and it will work due to "lifetime extension". If the non-const binding were allowed, it's presumed that lifetime extension would apply to it also. – ndkrempel Nov 21 '18 at 17:23
  • 1
    (For example: lifetime extension already applies to `String&& a = ...`, and that would also work in your example currently.) – ndkrempel Nov 21 '18 at 17:34