Passing by reference "advanced" concept? - c++

When you do this:
int square(int& x) { return x*x;};
int s = square(40); // This gives error
To fix this you do this:
int square(const int& x) { return x*x;};
int s = square(40); // This is OK
I understand that 40 is a constant but so what if I do this:
const int& x = 40
Why would that be okay only with const keyword? Is that the way the compiler protect that no one can change the value referred to by x?
40 is a const so we don't even know its location in memory, but shouldn't the compiler know this address, therefore changing the value from 40 to 30 for example should be allowed since the compiler can just go to address &40 and change the value to 30?

Just because it's possible to implement doesn't mean you should do it. Having 40 really be 30 is hilarious but especially unmaintainable and should not be permitted. In addition, 40 doesn't necessarily actually have an address. Consider a 40 in cache, register, or an immediate instruction.

The declaration of square:
int square(int& x);
takes a lvalue, while invocation of square(40) takes a rvalue, this is inconsistent, see more of lvalue and rvalue here.

The rules about references is that you cannot bind a temporary to non-const lvalue reference. The literal 40 can be used to initialize a temporary but it is, itself, not an object. Thus, you cannot bind a non-const lvalue reference to it.
When you do
int const& value = 40;
you actually bind a temporary object initialized to be 40 to the reference value. Normally, temporaries go out of scope and are destroyed at the end of a full-expression. However, when you directly bind a temporary to a non-const reference its life-time is extended to match the life-time of the reference.
The rules prohibiting binding of temporary objects to non-const references is in place primarily because it would probably cause many surprising results. It could technically be done but would be quite likely to produce non-obvious results.

You're confusing constants and literals. They are similar, but not equivalent. 40 is not a constant, it's a literal.
You can't pass a literal by reference, since if you pass something by reference, it means it can be modified - literals cannot. Consider the following:
void foo(int &i)
{
i = 1;
}
foo(0); // What on Earth? 0 == 1?
If you, however, pass a reference to a constant, it means that even if it's a reference, the function is not permitted to modify its argument (since it's a constant), so now you can safely pass in a literal - it now makes sense, since there's no possibility for the function modifying its argument.

You can still do:
int x = 40;
int s = square(x)
x = 30;
s = square(x);
with both versions of square (the one or without const).
When you pass something by reference you are passing an existing object (because that is what a reference means an alias to an existing object).
In your example:
int s = square(30);
You are NOT passing an object. This is a literal (they are not objects). The compiler can convert literals into object by creating a temporary object. But the language has explicit restrictions on temporary object that mean they are const. This means references can not be passed to an interface where they will be mutated (though you can pass them by const reference).

Related

What does "int*&&" do in C++?

I'm coming from a C# background and trying to learn a little C++.
I came across the following lines:
int x[3] = { 1, 2, 3 };
int*&& y = x;
int* z = y;
I know what pointers and arrays are and have some small understanding on lvalue and rvalue references. However I can't wrap my head around what int*&& y = x; actually does.
It would read like it creates a pointer to an rvalue reference, is this correct? What would be the use case of something like that, e.g. what is going on in memory if we execute this?
int*&& y = x; declares y to be a rvalue reference to pointer to int and initializes it with x. (Note that pointer to reference types (e.g. int&&*) do not exist in C++.)
Now the issue is that x is an array of int, not a pointer to int. So the reference can't bind directly to x. The types are not reference-compatible.
In such a situation (if the reference is either a rvalue reference or a const lvalue reference) an (unnamed) temporary object of the referenced type is created and the reference binds to that object instead. In this case an int* object is created and initialized with x, which by array-to-pointer decay means that the int* temporary object will be initialized to point to the first element of the array x.
Temporary objects normally live only until the end of the (full-)expression in which they are created, but in this case, because a reference is immediately bound to it, so-called temporary lifetime extension applies and the temporary int* object will live as long as the reference does (i.e. until the end of the reference's scope).
In other words it is (mostly) equivalent to
int* /*unnamed*/ = x;
int*&& y = /*unnamed*/;
where the comment /*unnamed*/ is supposed to represent the non-existing name of the temporary object.
When a reference's name is used in an expression (and this is completely independent of whether or not it is a lvalue or rvalue reference), it behaves exactly the same as if the object to which the reference is bound would have been named instead (but with the type of the reference with reference-qualifiers stripped which may e.g. differ by a const).
In other words int* z = y; behaves equivalently to int* z = /*unnamed*/;. So z is intialized from the temporary int* object, which has a pointer value pointing to the first element of the x array. For scalar types like int* initialization is simply copying the value, so z will also be initialized to point to the first element of x.
The whole thing is needlessly convoluted. It is exactly equivalent to int* z = x;. Using rvalue references usually only really makes sense as function parameters and some constructs where type deduction occurs. The important difference between lvalue and rvalue references is that they affect overload resolution differently and that they may be initialized with different value categories. There is also one special case in type deduction where rvalue references behave differently (as so-called forwarding references). Aside from that there is no difference between the different kinds of references.
what is going on in memory if we execute this?
That's mostly an implementation detail that shouldn't matter. You have an array that is stored somewhere depending on where you put these lines in your program. It is likely to be physically present somewhere in memory if the compiler doesn't figure it isn't needed. The reference y, the temporary int* which it points to and the z pointer may or may not actually be physically present in some memory, but the compiler is likely to just reduce all of them directly to the array. In particular, on the language level, references are not object and do not have storage (e.g. they don't have a memory size or location). If the compiler needs some memory to implement them (e.g. as a pointer), then that is purely an implementation detail of the compiler.

Keep constant reference to return value of function in C++

If I keep a constant reference to a non-reference returned value of a function in C++11, where does the reference point in the stack? And is it safe to do so?
string foo() {
std::string foo_ret = "foo string";
return foo_ret;
}
int main() {
const std::string& a = foo();
}
Your code is illegal; non-const lvalue references may not bind to rvalues. There's not really a good reason behind this, it's just a language rule that was introduced very early on in C++'s history.
MSVC used to (maybe still does) allow this binding, I can't comment on how MSVC implements it.
You can bind to other reference types though:
std::string const &a = foo(); // (1)
std::string&& b = foo(); // (2)
In case (2), b binds directly to the return value object, which has its lifetime extended to match b's lifetime. Note: no "move" operation occurs here, it is just binding a reference.
In case (1), conceptually, a temporary of type const std::string is initialized from the return value, and that temporary has its lifetime extended to match a's lifetime. In practice this copy will be elided. your code will behave as if the reference bound directly to the return value.
Generally speaking, you should use value semantics. std::string c = foo(); is the safest option. Because of copy elision, it is not any less efficient than the reference options.
The main danger with the reference option is that if the function were changed to return a reference, then a or b may become a dangling reference.
No it is not safe to do so, and it is an error and will not compile.
You might be looking for R Value references: http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html
In my opinion, it is legal to to do.
When you return a string from the function, it returns a Rvalue or temporary object. You can not use normal Lvalue reference to fetch the Rvalue but you can use const Lvalue reference to fetch. When you use const Lvalue reference, the life time of the temporary object is extended to be the same as the reference does.
As for where the reference point to in the memory, I guess it may vary by implementation. But what matters here is that the temporary object is no longer 'temporary', although you can not change it.

can we assign a integer value to a reference variable?

It is not possible to assign an integer value to a reference variable directly, say like:
int &x=10; //not possible
Is there any other way we can modify this statement to make it possible?
But not like this:
int a=10;int &x=a;
This works fine. But I want some other way or modify a little bit my expression and make it work!
The reference as the name says has to reference to something. How do you want to assign a value to it if it doesn't reference anything?
The reason it doesn't work is because 10 is of the type "const int". You can turn that into a reference, but you can't make it non-const without violating some logic at the least.
const int &a = 10;
that'll work.
int &b = const_cast<int &>(static_cast<const int &>(10));
will also compile, but you can't modify b (as that would imply modifying the actual "10" value).
The crux is that 10 is a constant – somewhat obviously: you cannot change its value. But if you try to assign it to an int reference, this would mean that the value were modifiable: an int& is a modifiable value.
To make your statement work, you can use a const reference:
int const& x = 10;
But as “cnicutar” has mentioned in a comment, this is pretty useless; just assign the 10 to a plain int.
You can't bind a reference-to-nonconst to anything immutable.
The standard permits storing compile time constants in ROM (btw, attempting to modify const_cast<>ed compile time constants yields undefined behaviour)
This would basically strip of the const, even if the const is invisible, therefore subverting the whole const-correctness-thing
However, you can bind a reference-to-const to nearly everything, including temporaries:
GotW: A candidate for the most important const
Consider this a "feature".
References refer to objects (perhaps temporary objects), not to values. If you want to store a value somewhere, assign it to an object, not to a reference.
As a special case, const int &a = 10; initializes the reference a to refer to a temporary object with the value 10, and it extends the lifetime of that temporary to the end of the scope of a (12.2/5). That's pretty useless with an integer literal, but occasionally useful with objects of class type. Still, this does not assign an integer value to a reference. It creates a temporary, and binds a reference to the temporary.
in the C++0x, you can use int&& (rvalue references ), but this can be used as function parameter.

Integral promotion when passing and returning argument by reference?

I'm reading something about overload resolution and I found something that bothers me...In the following code:
int const& MaxValue(int const& a, int const& b)
{
return a > b ? a : b;
}
void SomeFunction()
{
short aShort1 = 3;
short aShort2 = 1;
int const & r2 = MaxValue(aShort1, aShort2); // integral promotion
//is it safe to pass r2 around before function SomeFunction completes
// CallSomeOtherFunctionThatCallsSomethingElse(r2);
}
My understanding is that two temporary int's are created and they're allocated on the stack belonging to SomeFunction.
So when MaxValue returns, r2 referencing to one of those temp variables (in this case, the one that holds value 3).
Thus, is should be safe to pass r2 around.
The question is, if my understanding is fine, is this a standard behavior (please verify)? If not, please explain what is happening in above code.
Many Thanks
Welcome to why implicit casts suck. You now have a reference to a temporary, which has been destroyed. Hope you didn't want to do anything with it.
Yes, your understanding is fine and this is standard behaviour.
Except this:
Thus, is should be safe to pass r2 around.
which I do not understand.
// EDIT
You should use pointers instead of references here to achieve the same but without the problem. Using address of an argument passed by const reference is OK only within the function because it may point to local copy of an object.
Short answer: it is unsafe.
The standard guarantees that a temporary variable can be bound to a constant reference in which case the lifespan of the temporary expands to the lifetime of the bound reference. The problem in your particular case is what reference is actually binding the temporary.
When you call MaxValue( s1, s2 ), two temporary variables of type int are created and bound to the parameter arguments a and b in MaxValue. This means that the lifespan of those temporaries is extended to the completion of the function. Now, in the return statement of your function you are taking a second reference to one of the temporaries and that second reference will not extend the lifetime. r2 will not further extend the lifetime of the object, and you have a dangling reference.
Note that due to the separate compilation, the compiler cannot possibly know from outside of MaxValue whether the returned reference is to one of the arguments or to a completely different object that is not a temporary:
int const & OtherMaxValue( int const & a, int const & b ) {
static int value = 0;
value = (a > b? a : b);
return value;
}
So it cannot possibly guess whether any or which of the temporaries lifetime needs to be extended.
As a side note, for small objects (such as all integer types) passing by reference may be actually worse than passing by value. Also there is already an std::max template that actually implements this functionality.
You should return and pass by value for simple types.

Are all temporaries rvalues in C++?

I have been coding in C++ for past few years. But there is one question that I have not been able to figure out. I want to ask, are all temporaries in C++, rvalues?
If no, can anyone provide me an example where temporary produced in the code is an lvalue?
No.
The C++ language specification never makes such a straightforward assertion as the one you are asking about. It doesn't say anywhere in the language standard that "all temporary objects are rvalues". Moreover, the question itself is a bit of misnomer, since the property of being an rvalue in the C++ language is not a property of an object, but rather a property of an expression (i.e. a property of its result). This is actually how it is defined in the language specification: for different kinds of expressions it says when the result is an lvalue and when it is an rvalue. Among other things, this actually means that a temporary object can be accessed as an rvalue as well as an lvalue, depending on the specific form of expression that is used to perform the access.
For example, the result of literal 2 + 3 expression is obviously an rvalue, a temporary of type int. We cannot apply the unary & to it since unary & requires an lvalue as its operand
&(2 + 3); // ERROR, lvalue required
However, as we all know, a constant reference can be attached to a temporary object, as in
const int &ri = 2 + 3;
In this case the reference is attached to the temporary, extending the lifetime of the latter. Obviously, once it is done, we have access to that very same temporary as an lvalue ri, since references are always lvalues. For example, we can easily and legally apply the unary & to the reference and obtain a pointer to the temporary
const int *pi = &ri;
with that pointer remaining perfectly valid as long as the temporary persists.
Another obvious example of lvalue access to a temporary object is when we access a temporary object of class type through its this pointer. The result of *this is an lvalue (as is always the case with the result of unary * applied to a data pointer), yet it doesn't change the fact that the actual object might easily be a temporary. For a given class type T, expression T() is an rvalue, as explicitly stated in the language standard, yet the temporary object accessed through *T().get_this() expression (with the obvious implementation of T::get_this()) is an lvalue. Unlike the previous example, this method allows you to immediately obtain a non-const-qualified lvalue, which refers to a temporary object.
So, once again, the very same temporary object might easily be "seen" as an rvalue or as an lvalue depending on what kind of expression (what kind of access path) you use to "look" at that object.
Prasoon Saurav already linked a very good clc++ thread. In there, James Kanze explains why the question doesn't really make sense. It boils down to:
rvalue-ness is a (boolean) property of expressions - each expression is either an lvalue or an rvalue
temporaries are not expressions
For that reason, the question doesn't make sense.
A good example is the following code:
int main() {
const int& ri = 4;
std::cout << ri << std::endl;
}
The temporary int with value 4 is not an expression. The expression ri that's printed is not a temporary. It's an lvalue, and refers to a temporary.
well, that array operator returns a reference, any function that returns a reference could be considered to do the same thing? all references are const, while they can be lvalues, they modify what they reference, not the reference itself. same is true for the *operator,
*(a temp pointer) = val;
I swear I used to use some compiler that would pass temp values to any function that took a reference,
so you could go:
int Afunc()
{
return 5;
}
int anotherFunc(int & b)
{
b = 34;
}
anotherFunc(Afunc());
can't find one that lets you do that now though, the reference has to be const in order to allow passing of temp values.
int anotherFunc(const int & b);
anyway, references can be lvalues and temporary, the trick being the reference it's self is not modified, only what it references.
if you count the-> operator as an operator, then temporary pointers can be lvalues, but the same condition applies, its not the temp pointer that would be changed, but the thing that it points to.
An array indexing operation is both a temporary and an lvalue, something like a[10] = 1 is an example of what you're looking for; the lvalue is a temporary, calculated pointer.
Short answer: yes, but I'm not going to quote the standard, because proving the point would require addressing every kind of temporary there is. By definition a temporary has a lifetime of one statement, so assigning things to one would be poor style at best.
Interesting answer: Copy elision can make (often makes) a temporary object identical with an lvalue object. For example,
MyClass blah = MyClass( 3 ); // temporary likely to be optimized out
or
return MyClass( 3 ); // likely to directly initialize object in caller's frame
Edit: as for the question of whether there is any temporary object in those cases, §12.8/15 mentions
the copy operation can be omitted by constructing the temporary object directly into the target of the omitted copy
which would indicate that there is a temporary object which may be identical with an lvalue.
It depends on what you consider a temporary variable is. You can write something like
#include <stdio.h>
int main()
{
char carray[10];
char *c=carray+1;
*(c+2+4) = 9;
printf("%d\n",carray[7]);
return 0;
}
This runs in VisualStudios and GCC. You can run the code in codepad
I consider (c+2+4) a rvalue although i want to assign to it. When i dereference it, it would become an lvalue. So yes all temporaries are rvalues. But you can make rvalues (thus a temporary) into an lvalue by dereferencing it
If no, can anyone provide me an example where temporary produced in the code is an lvalue?
The following code binds a constant reference to a temporary object of type const float created by the compiler:
int i;
const float &cfr = i;
The behaviour is "as if":
int i;
const float __tmp_cfr = i; // introduced by the compiler
const float &cfr = __tmp_cfr;