Is this a copy? but why it works like a reference? - c++

The below code, Value r = foo(i), is r a reference or a copy?
Value foo(int i) {
return Value::New(i);
}
Value bar(Arg x) {
// should I use Value& r = foo(x.getIndex());
Value r = foo(x.getIndex());
x.close();
return r;
}
I tested
#include <stdio.h>
using namespace std;
class Value {
public:
Value() {
printf("construct\n");
}
};
Value foo(){
Value a;
return a;
}
Value bar() {
Value b = foo();
return b;
}
int main(){
Value c = bar();
}
only construct 1 times.

Depends. If Value is typedef'd to some reference type (e.g. int&) then yes, foo would be a reference. Otherwise no. As Paolo points out, however, Value has a member function New and thus cannot be a reference type. Therefore you are passing/returning Values by copy, not by reference.
Post Edit: The reason you don't see your string message printed several times is simple: It's only printed when the default ctor is invoked. Implement an actual copy-ctor and you will see a lot more messages, each time a Value is copied.

Copy. You would notice reference by the & sign.
The real question is what foo returns. If it returns a reference - it makes sense to use a reference, otherwise if it returns a copy (i.e.: the return type is Value, not Value&), you'll just be referencing a copy, so what's the point (and you would probably get a compiler warning or error)?

It's a copy. Also, you can't use a reference there (as in the commented line), because the return value of foo is stored in a temporary and gets destructed at the end of the line, creating a dangling reference.

Copy, because foo(int) does not return a reference.

It is a copy for two reasons. The first one,as pointed by others, is that foo returns a copy of Value, i.e. it does not return Value &.
The second reason is that this (misleading) syntax
Value r = foo(x.getIndex());
Does not have anything to do with the assignment operator, it is actually equivalent to:
Value r( foo( x.getIndex() ) );
The new object of class Value is built with another instance of class Value, so the copy constructor is invoked.
About the question in your source code:
Value bar(Arg x) {
// should I use Value& r = foo(x.getIndex());
Value r = foo(x.getIndex());
x.close();
return r;
}
No, you shouldn't use Value&, since in order to keep it effective you should change the return value of bar to Value&, and you cannot return a reference to an object that will be end its life when the bar() function ends.
Hope this helps.

Edit for the updated question:
only construct 1 times
Because the standard explicitly allows the compiler to optimize away copy construction (even if it has side affects). Your code is easily optimized by the compiler using RVO and NRVO. This basically allows the compiler to construct the object once at the destination (thus you see no copies).
Original Answer
Its a copy
The function foo() returns a value of type Value
Value foo(int i)
If you want to return a reference to an object of type value you need to indicate this in the function signature:
Value & fooRef(int i)
// ^^^ Notice the & symbol
Also the variable 'r' is an object. So even if you assign a reference to it. It will then make a copy of the original object returned.
Value rv = fooRef(1); // fooRef() returns a reference to an object.
// But here we make a copy into rv
Value& rf = fooRef(1); // fooRef() returns a reference.
// rf is a reference and keeps a reference to the object returned by
// fooRef()

Related

Returning a reference to an implicitly constructed parameter vs an implicitly constructed internal object

C++11 question
Trying to understand an issue I came across in our code. Not looking for the "right" way to do this, just want to know how this is supposed to work so I can figure out how to fix things in the future
I think function f1() is fine returning a reference to the temp implicitly constructed on the same line as the p1
But what about p2? The temp is constructed implicitly in the body of f2() when calling f1(), but f2() is returning the reference that is being returned by f1(). I thought the lifetime of the temp is extended to match the lifetime of the reference
asking because in one of our compilers p2 is garbage on the next time, but on the others it is not
struct PP
{
int i;
PP(int i_) : i(i_) {}
};
const PP &f1(const PP &p)
{
return p;
}
const PP &f2(int i)
{
return f1(i);
} // does the temp live here after return?
int main()
{
const PP &p1 = f1(1);
const PP &p2 = f2(2); // is p2 valid on the NEXT line
return 0;
}
I think this is undefined behaviour, and the fact that different compilers have different outputs would suggest that.
In f2, you're returning a reference constructed by f1, which itself has a reference to the local object i. At the end of the scope, i dissapears and invalidates the reference.
In fact clang-tidy detects this godbolt example
Also in reference initialization of cppreference it states, as an exception to lifetime extension:
a temporary bound to a return value of a function in a return
statement is not extended: it is destroyed immediately at the end of
the return expression. Such return statement always returns a dangling
reference.

Why cannot assign value to non-const reference?

Why these definitions are all ok:
int func(int p=255) {
return p;
}
int func1(const int &p=255) {
return p;
}
but this definition:
int func2(int &p=255) {
return p;
}
leads to compile error ?
What is the logic behind it ?
Taking arguments by reference means, you dont work with your local copy of the variable, but with a variable already defined in the scope of the calling function.
While your first example makes sense (you have a local variable p that you can fill with a default value) the second example is a bit more tricky: Usually when using references you expect the variable to have an address, since you want to modify it. For const-refernces, the compiler will still allow you to pass a literal, even if something like "reference to a literal" makes no sense at all.
In the third case the compiler expects you to modify p. But what part of the memory should this modification affect? "255" has no address - therefore it cant be used as a reference.
If you want to have a more detailed explanation, you should probably look for keywords like "rvalue" and "lvalue".
The attempted function definition
auto func2( int& p = 255 )
-> int
{ return p; }
… fails because you can't bind an rvalue to a reference to non-const. Basically that rule is because a simple value like 255 isn't modifiable. While the reference can be used to modify.
One simple solution is to express the default as a separate overload:
auto func2( int& p )
-> int
{ return p; }
auto func2()
-> int
{
int scratchpad = 255;
return func2( scratchpad );
}
A non-const reference must be bound to lvalue (i.e. its address could be got). 255 (i.e. an int literal) is not a lvalue, so int &p=255 fails.
A const reference could be bound to rvalue, and for this case, a temporary int will be created and initialized from 255. The temporary int's lifetime will be the same as the const reference.
int func(int p=255) {
return p;
}
p here is copied by value, and it is defined to exist in the scope of func.
int func2(int &p) {
return p;
}
// e.g. use:
int value = 10;
func2(value); // func2 *could* modify value because it is passed by non-const reference
In this case the compiler here expects p to have a name somewhere in memory (i.e. lvalue), so it can possibly write to it within func2. Passing by non-const reference allows you to modify the variable used in the function call. Since p must belong to someone else somewhere since it can be modified, you can't assign a default value to it.
But what about the const-reference case? Here, the compiler is smart enough to know that p can never be written to since it is const, so it doesn't need to have a name in memory to write to. In cases of a literal being passed (e.g. 255), it (behind the scenes) essentially creates a temporary and passes that temporary variable to the function.
int func1(const int &p=255) {
return p;
}
func1(10);
// Behind the scenes, the compiler creates something along these lines
// since it can never be modified.
const int some_temporary = 10;
func1(some_temporary);

Assigning value to function returning reference

#include<iostream>
using namespace std;
int &fun()
{
static int x = 10;
return x;
}
int main()
{
fun() = 30;
cout << fun();
return 0;
}
Function fun() is returning value by reference but in main() method I am assigning some int to function. Ideally, a compiler should show an error like lvalue required but in above case the program works fine. Why is it so?
It's loose and sloppy language to say "a function returns something". It's OK as a shorthand if you know how to work with that, but in this case you get confused.
The more correct way to think about it is that you evaluate a function call expression. Doing that gives you a value. A value is either an rvalue or an lvalue (modulo details).
When T is an object type and you evaluate a function that has return type T, you get a value of type T which is an rvalue. On the other hand, if the function has return type T &, you get a value of type T which is an lvalue (and the value is the thing bound to the reference in the return statement).
Returning a reference is quite useful.
For example it's what std::map::operator[] does. And I hope you like the possibility of writing my_map[key] = new_value;.
If a regular (non-operator) function returns a reference then it's ok to assign to it and I don't see any reason for which this should be forbidden.
You can prevent assignment by returning a const X& or by returning X instead if you really want.
You can rewrite the code using pointers, which might be easier to understand:
#include<iostream>
using namespace std;
int *fun() //fun defined to return pointer to int
{
static int x = 10;
return &x; // returning address of static int
}
int main()
{
*fun() = 30; //execute fun(), take its return value and dereference it,
//yielding an lvalue, which you can assign to.
cout << *fun(); //you also need to dereference here
return 0;
}
References can be very confusing from a syntax point of view, as the dereferencing of the underlying "pointer" is implicitly done by the compiler for you. The pointer version looks more complicated, but is clearer or more explicit in its notation.
PS: Before someone objects to me regarding references as being a kind of pointer, the disassembly for both code versions is 100% identical.
PPS: Of course this method is a quite insidious breach of encapsulation. As others have pointed out, there are uses for this technique, but you should never do something like that without a very strong reason for it.
It works becuse the result of that function is an lvalue. References are lvalues. Basically, in the whole point of returning a non-const reference from a function is to be able to assign to it (or perform other modifications of referenced object).
In addition to other answers, consider the following code:
SomeClass& func() { ... }
func().memberFunctionOfSomeClass(value);
This is a perfectly natural thing to do, and I'd be very surprised if you expected the compiler to give you an error on this.
Now, when you write some_obj = value; what really happens behind the scenes is that you call some_obj.operator =(value);. And operator =() is just another member function of your class, no different than memberFunctionOfSomeClass().
All in all, it boils down to:
func() = value;
// equivalent to
func().operator =(value);
// equivalent to
func().memberFunctionOfSomeClass(value);
Of course this is oversimplified, and this notation doesn't apply to builtin types like int (but the same mechanisms are used).
Hopefully this will help you understand better what others have already explained in terms of lvalue.
I was buffled by similar code too - at fist. It was "why the hell I assign value to a function call, and why compiler is happy with it?" I questioned myself. But when you look at what happens "behind", it does make sense.
As cpp and others poined out, lvalues are "memory locations" that have address and we can assign values to them. You can find more on the topic of lvalues and rvalues on the internet.
When we look at the function:
int& fun()
{
static int x = 10;
return x;
}
I moved the & to the type, so it's more obvious we are returning a reference to int.
We see we have x, which is lvalue - it has address and we can assign to it. It's also static, which makes it special - if it wasn't static, the lifetime (scope) of the variable would end with stack unwinding upon leaving the function and then the reference could point to whatever black hole exists in the universe. However as x is static, it will exist even after we leave the function (and when we come back to the function again) and we can access it outside of the function.
We are returning reference to an int, and since we return x, it's reference to the x. We can then use the reference to alter the x outside of the function. So:
int main()
{
fun();
We just call the function. Variable x (in scope of fun function) is created, it has value of 10 assigned. It's address and value exist even after function is left - but we can't use it's value, since we don't have it's address.
fun() = 30;
We call the function and then change the value of x. The x value is changed via the reference returned by the function. NOTE: the function is called first and only after the function call was completed, then, the assignment happens.
int& reference_to_x = fun(); // note the &
Now we (finally) keep the reference to x returned by the function. Now we can change x without calling the function first. (reference_to_x will probably have the same address as the x have inside the fun function)
int copy_of_x = fun(); // no & this time
This time we create new int and we just copy the value of x (via the reference). This new int has its own address, it doesn't point to the x like reference_to_x is.
reference_to_x = 5;
We assigned x the value 5 through the reference, and we didn't even called the function. The copy_of_x is not changed.
copy_of_x = 15;
We changed the new int to value 15. The x is not changed, since copy_of_x have its own address.
}
As 6502 and others pointed out, we use similar approach with returning references a lot with containers and custom overrides.
std::map<std::string, std::string> map = {};
map["hello"] = "Ahoj";
// is equal to
map.operator[]("hello") = "Ahoj"; // returns reference to std::string
// could be done also this way
std::string& reference_to_string_in_map = map.operator[]("hello");
reference_to_string_in_map = "Ahoj";
The map function we use could have declaration like this:
std::string& map::operator[]( const std::string& key ); // returns reference
We don't have address to the string we "stored" in the map, so we call this overridden function of map, passing it key so map knows which string we would like to access, and it returns us reference to that string, which we can use to change the value. NOTE: again the function is called first and only after it was completed (map found the correct string and returned reference to it) the assignment happens. It's like with fun() = 10, only more beatiful...
Hope this helps anyone who still woudn't understand everything even after reading other answers...
L-value is a locator-value. It means it has address. A reference clearly has an address. The lvalue required you can get if you return from fun() by value:
#include<iostream>
using namespace std;
int fun()
{
static int x = 10;
return x;
}
int main()
{
fun() = 30;
cout << fun();
return 0;
}

How to get a pointer from a reference?

There seems to be many relavent questions talking about pointer vs. reference, but I couldn't find what I want to know. Basically, an object is passed in by a reference:
funcA(MyObject &objRef) { ... }
Within the function, can I get a pointer to that object instead of the reference? If I treat the reference objRef as an alias to the MyObject, would &objRef actually give me a pointer to the MyObject? It doesn't seem likely. I am confused.
Edit: Upon closer examination, objRef does give me back the pointer to object that I need - Most of you gave me correct info/answer, many thanks. I went along the answer that seems to be most illustrative in this case.
Yes, applying the address-of operator to the reference is the same as taking the address of the original object.
#include <iostream>
struct foo {};
void bar( const foo& obj )
{
std::cout << &obj << std::endl;
}
int main()
{
foo obj;
std::cout << &obj << std::endl;
bar( obj );
return 0;
}
Result:
0x22ff1f
0x22ff1f
Any operator applied to a reference will actually apply to the object it refers to (§5/5 [expr]); the reference can be thought of as another name for the same object. Taking the address of a reference will therefore give you the address of the object that it refers to.
It as actually unspecified whether or not a reference requires storage (§8.3.2/4 [dcl.ref]) and so it wouldn't make sense to take the address of the reference itself.
As an example:
int x = 5;
int& y = x;
int* xp = &x;
int* yp = &y;
In the above example, xp and yp are equal - that is, the expression xp == yp evaluates to true because they both point to the same object.
The general solution is to use std::addressof, as in:
#include <type_traits>
void foo(T & x)
{
T * p = std::addressof(x);
}
This works no matter whether T overloads operator& or not.
Use the address operator on the reference.
MyObject *ptr = &objRef;
Use the address-of (&) operator on the reference.
&objRef
Like any other operator used on a reference, this actually affects the referred-to object.
As #Kerrek points out, since the operator affects the referred-to object, if that object has an overloaded operator& function, this will call it instead and std::address_of is needed to get the true address.
In C++, a reference is a restricted type of pointer. It can only be assigned once and can never have a NULL value.
References are most useful when used to indicate that a parameter to a function is being Passed by Reference where the address of the variable is passed in. Without a Reference, Pass By Value is used instead.

Does dereferencing a pointer make a copy of it?

Does dereferencing a pointer and passing that to a function which takes its argument by reference create a copy of the object?
In this case the value at the pointer is copied (though this is not necessarily the case as the optimiser may optimise it out).
int val = *pPtr;
In this case however no copy will take place:
int& rVal = *pPtr;
The reason no copy takes place is because a reference is not a machine code level construct. It is a higher level construct and thus is something the compiler uses internally rather than generating specific code for it.
The same, obviously, goes for function parameters.
In the simple case, no. There are more complicated cases, though:
void foo(float const& arg);
int * p = new int(7);
foo(*p);
Here, a temporary object is created, because the type of the dereferenced pointer (int) does not match the base type of the function parameter (float). A conversion sequence exists, and the converted temporary can be bound to arg since that's a const reference.
Hopefully it does not : it would if the called function takes its argument by value.
Furthermore, that's the expected behavior of a reference :
void inc(int &i) { ++i; }
int main()
{
int i = 0;
int *j = &i;
inc(*j);
std::cout << i << std::endl;
}
This code is expected to print 1 because inc takes its argument by reference. Had a copy been made upon inc call, the code would print 0.
No. A reference is more or less just like a pointer with different notation and the restriction that there is no null reference. But like a pointer it contains just the address of an object.