In what situation would generate an error if you don't return something by reference for a function?
In what situation would generate an error if you don't return something by reference for a function?
Restricting the answer to what is being exactly asked,
Whenever you want the return value of the function to act as an l-value, and you do not return by reference then it will generate an error.
The more common example of this is overloading the operator [](the array subscription operator), You have to return by reference in order to use the [] on the l.h.s or more correctly to use it as an l-value.
An example:
class Myclass
{
int i;
public:
/*Not returned by reference- gives error*/
int operator[](int idx){ return i;}
/*Returned by reference- gives no error*/
//int& operator[](int idx){ return i;}
};
int main()
{
Myclass obj;
obj[1]= 10;
return 0;
}
Output:
prog.cpp: In function ‘int main()’:
prog.cpp:16: error: lvalue required as left operand of assignment
The default action should be to return by value. The main case where
you'ld want to return a reference is when you want to expose some
“part” of a larger object; e.g. an element in a vector or a
map. The important thing is that the object referred to must have a
lifetime beyond that of the calling function.
The question should be when is it not safe to return by reference. Whenever you return a variable local to a method by reference, you're invoking undefined behavior.
It's unsafe to return by value when you haven't correctly implemented the copy constructor.
You'd get an error if copy constructor was declared private and you'd try to return by value.
Related
I'm confused between the subtle differences of passing vectors
This is some part of my program
void print(vector<vector<char>>&field)
vector<vector<char>> bomb(vector<vector<char>>&field)
I encountered a case where I can't do something like this
print((bomb(bomb(field)));
The error is
error: invalid initialization of non-const reference of type 'std::vector<std::vector<char> >&' from an rvalue of type 'std::vector<std::vector<char> >'
print(bomb(bomb(field)));
But if I add a const to the method definition to
void print(const vector<vector<char>>&field)
vector<vector<char>> bomb(const vector<vector<char>>&field)
Then this will work
What is the difference between
1. vector<vector<char>> bomb(vector<vector<char>>&field)
3. vector<vector<char>> bomb(const vector<vector<char>>&field)
4. vector<vector<char>> bomb(const vector<vector<char>>field)
I believe 1 is passing a vector by reference, which is what I've been doing before. How come I can't do something like bomb(bomb(field)) without the compiler complaining?
The return value of bomb is an object, not a reference. The return value is a temporary object. Hence, you cannot use it when the expected type is a non-const reference.
Analogy with simpler objects:
int foo(int& i) { return i+2; }
void bar(int& i) {}
// Can't use
int i = 10;
bar(foo(i));
That is a problem since foo returns a temporary object. Its return value cannot be used as an argument to bar since bar expects a non-const reference.
If the return value of bomb can be changed to a reference,
vector<vector<char>>& bomb(const vector<vector<char>>&field);
without breaking how it works, then you can use:
print((bomb(bomb(field)));
MyObject& MyObject::operator++(int)
{
MyObject e;
e.setVector(this->vector);
...
return &e;
}
invalid initialization of non-const reference of type 'MyObject&' from an rvalue of type 'MyObject*'
return &e;
^
I am not sure what it's saying. Is it saying that e is a pointer, because it's not a pointer. Also, if you'd make a pointer to the address of e, it would get wiped out at the end of the bracket and the pointer would be lost.
Your return type is MyObject&, a reference to a (non-temporary) MyObject object. However, your return expression has a type of MyObject*, because you are getting the address of e.
return &e;
^
Still, your operator++, which is a postfix increment operator due to the dummy int argument, is poorly defined. In accordance to https://stackoverflow.com/a/4421719/1619294, it should be defined more or less as
MyObject MyObject::operator++(int)
{
MyObject e;
e.setVector(this->vector);
...
return e;
}
without the reference in the return type.
You're correct that e is not a pointer, but &e very much is a pointer.
I'm reasonably certain that returning a reference to a stack variable that will be out of scope before you can use it is also not such a good idea.
The general way to implement postfix operator++ is to save the current value to return it, and modify *this with the prefix variant, such as:
Type& Type::operator++ () { // ++x
this->addOne(); // whatever you need to do to increment
return *this;
}
Type Type::operator++ (int) { // x++
Type retval (*this);
++(*this);
return retval;
}
Especially note the fact that the prefix variant returns a reference to the current object (after incrementing) while the postfix variant returns a non-reference copy of the original object (before incrementing).
That's covered in the C++ standard. In C++11 13.6 Built-in operators /3:
For every pair (T, VQ), where T is an arithmetic type, and VQ is either volatile or empty, there exist candidate operator functions of the form:
VQ T & operator++(VQ T &);
T operator++(VQ T &, int);
If, for some reason, you can't use the constructor to copy the object, you can still do it the way you have it (creating a local e and setting its vector) - you just have to ensure you return e (technically a copy of e) rather than &e.
Change return &e; to return e;. In the same way that a function like
void Func(int &a);
isn't called with Func(&some_int) you don't need the & in the return statement. &e takes the location of e and is of type MyObject*.
Also note, MyObject& is a reference to the object, not a copy. You are returning a reference to e, which will be destroyed when the function finishes and as such will be invalid when you next make use of it.
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()
this is an assignment operator. &rhs != this is confusing. my questions: rhs is a reference of Message type. What does &rhs mean? what does & do (a memory address of a reference?)?
Another question is about return *this . since we want a reference to type Message, but *this is a Message typed object, right? How can we return an object to a reference?
Message& Message::operator=(const Message &rhs)
{
if (&rhs != this)
{
some functions;
}
return *this;
}
&rhs means address of the object which reference is referecing to.
Message a;
const Message &rhs = a;
if (&rhs == &a) std::cout << "true" << std::endl;
This is will print true.
A reference is not a different object; it is just a syntactic sugar of pointer, which points to the same object whose reference it is. So when you write return this, it returns a pointer to the object, but if you write return *this, it returns either a copy of the object, or reference to the object, depending on the return type. If the return type is Message &, then you tell the compiler that "don't make a copy and instead return the same object". Now the same object is nothing but a reference. A reference of an object can be made anytime. For example, see the declaration of rhs above; it is const Message & rhs = a, since the targer type is mentioned as reference type, you're making a reference rhs of the object a. It is that simple.
Besides Nawaz's great answer, I want to point out that you have to be careful about returning a reference to a local variable which will go out of scope after function return. So avoid returning a reference like this:
string& foo()
{
string result = "abc";
return result;
}
which causes the following compiler warning:
reference to local variable result returned
A reference is just an alias to an object. References are formed by request of the function that is called; they are not (necessarily) part of an object's type. This is probably already familiar to you, but consider this:
void f1(int a) { ++a; }
void f2(int & a { ++a; }
int main()
{
int x = 5;
f1(x);
f2(x);
}
Surely you know the difference between the two functions. But note that x is always just an object of type int. Whether it is passed by reference or by value is not a property of x, but rather of the function.
The same goes for return types:
int q;
int g1() { return q; }
int & g2() { return q; }
int main()
{
++g2();
++g1(); // error
}
Again, q is just an object. Whether return q; returns it by value or by reference is not a property of q, but of the function. g1 makes a copy of q, while g2 returns a reference to the actual q object (which we can increment). (The return value of g1 cannot be incremented, precisely because it doesn't have a permanent existence and this would be meaningless (technially, the expression is an rvalue).)
So in you example, return *this; returns a reference to the object itself. That has nothing to do with this, but it has everything to do with the fact that the return type of the function is Message&.
In C++,
function() = 10;
Works if function returns a variable by reference, right?
Would someone please elaborate on this in detail?
Consider this piece of code first
int *function();
...
*function() = 10;
Looks similar, isn't it? In this example, function returns a pointer to int, and you can use it in the above way by applying a unary * operator to it.
Now, in this particular context you can think of references as "pointers in disguise". I.e. reference is a "pointer", except that you don't need to apply the * operator to it
int &function();
...
function() = 10;
In general, it is not a very good idea to equate references to pointers, but for this particular explanation it works very well.
Consider the following code, MyFunction returns a pointer to an int, and you set a value to the int.
int *i;
i = MyFunction();
*i = 10;
Are you with me so far?
Now shorten that to
*(MyFunction()) = 10;
It does exactly the same thing as the first code block.
You can look at a reference as just a pointer that's always dereferenced. So if my function returned a reference - not a pointer - to an int the frist code block would become
int &i;
i = MyFunction();
i = 10;
and the second would become
MyFunction() = 10;
You still with me?
With a little experiment, you can determine if this will work or not.
Considering this example:
class foo {
private:
int _val;
public:
foo() { _val = 0; }
int& get() { return _val; }
void print() { printf("val: %d\n", _val); }
};
int main(void) {
foo bar;
bar.print();
bar.get() = 10;
bar.print();
}
And it's output is:
val: 0
val: 10
So sure enough, it is possible to return a reference. Note that the variable being referenced may go out of scope, then your caller may get garbage results (just like dereferencing a pointer to an object that has gone out of scope). So this would be bad:
int& get() {
int myval = _val;
return myval;
}
The answer to this question has to do with rvalue semantics versus lvalue semantics. Every value in C++ is either an lvalue or an rvalue. Lvalues are values that are stored in an addressable memory location, which implies they are assignable (assuming they are non-const, of course.) An rvalue is basically anything else, e..g literal constants, or non-addressable temporary values.
So, a function which returns a non-const reference is an lvalue. However, a function which returns by value would be an rvalue expression, because it returns a non-addressable temporary value, and is therefore not assignable.
See the wikipedia entry for a more detailed explanation with examples given.
A question you did not ask.
But why would you want to do that?
Think of the std::vector (I am extending the principle to methods).
Here you have the method 'operator[]()' It retuns a reference to the internal member.
This then allows the following:
std::vector<int> x(20,1);
x[5] = 10;
// This is quivalent to:
x.operator[](5) = 10;
// So this is just a function (method) call:
x.function(5) = 10;
As others noted function can return reference to member variable, but word of caution: this function should not be a part of class interface. Once you provide a function that returns reference to internals of your class, you loose control over them.
If you have not yet read "Effective C++", do it.
Item 29 of the book says "Avoid returning "handles" to internal data" and explains in more details why this practice needs to be avoided.
A word of warning, when returning a reference: pay attention to the lifetime of whatever you're returning. This example is bad:
int &function()
{
int x;
// BAD CODE!
return x;
}
...
function() = 10;
x doesn't exist outside of function, and neither do any references to it. In order to return a reference from a function, the object being referred to has to last at least as long as the reference. In the above example, x would need to be declared static. Other possibilities would be making x a global variable, or making function a class member function and returning a reference to a class member variable, or allocating x on the heap and returning a reference to that (although that gets tricky with deallocation)