How does this return a reference? - c++

I've been trying to learn how to use a singleton design pattern and stumbled across this:
static S& getInstance()
{
static S instance;
return instance;
}
I noticed here that it returns instance, shouldn't it be supposed to return an instance&?
Edit: I should also mention that the compiler doesn't seem to be making any complaints.

return instance; does return a reference to instance. That is just like
int& r = a;
for some int a creates a reference to a without needing to write a& or something like this.

No, it's correct as written. The compiler will create and return a reference to instance from the function getInstance.
You ask whether it should be instance&. First of all, that is not syntactically valid. What about &instance then? That would take the address of instance and would, therefore, return an instance *.
The multiple uses of the & operator are a common source of confusion. Here's a quick "cheat-sheet" that doesn't use complex terminology from the standard:
The binary (two argument) version of & is applied against two instances of variables and represents bitwise AND (except when overloaded).
unsigned int a = 7;
unsigned int b = 3;
unsigned int c = a & b; // c = 3
The unary (one argument) version of & when applied to a type denotes a reference to a type. Example:
int a = 7;
int& ref_a = a; // ref_a is a reference to a
The unary (one argument) version of & when applied to a variable denotes the address-of operator and yields a pointer to the variable.
int a = 7;
int* ptr_a = &a;

Related

Why can the same expression be returned either by copy or by reference?

I know the differences between T& operator[](); and T operator[](), the former one returns a reference, the latter one returns a copy of the result.
But what confuses me is that the same expression container[idx] could be used in the return statement for the two different kinds of return types in the declarations.
How is this goal (one returns a reference, the other returns a copy) is achieved by the compiler?
Here is the code snippet:
template<typename T>
class Array
{
public:
#ifdef RETURN_REFERENCE
T& operator[](int idx)
#else
T operator[](int idx)
#endif
{
assert(idx<size);
return container[idx]; // same expression works for T and T&
}
private:
enum {size =100};
T container[size];
}
It's fundamentally no different from this case:
int i = <whatever>;
int &j = i; //Reference
int k = i; //Copy
The i expression does not stand alone. It is being used in a specific context, and the nature of that context determines what happens to the expression.
The return statement is performed in the context of the type of the return value. For example, if the returned expression is different from the type of the return value, the compiler will attempt to convert the expression to the appropriate type (much like float q = i; would convert i to a float).
The expression by itself just identifies an object. What happens to the object being identified depends on how it gets used. If it's used to initialize a reference, then a reference to that object is created. If it's used to initialize another object of that type, then a copy is created.

Pass by reference notation

My question is really straightforward and I believe understandable.
I've made this simple snippet to illustrate my conflict when I'm passing values by reference.
int main() {
int a = 1;
int &b = a;
}
I know that this is the correct way to do it but how does it make sense to take the address of b and make it equal to the value of a. Logically it should be: int &b = &a;
Many operators are context-sensitive. The & "operator" could mean three different things depending on context:
It could be used when defining a reference
int& r = a; // The variable r is a reference of the variable a
It could be used to get a pointer to something
int* p = &a; // Here & is the address-of operator which returns a pointer
// Here it makes p point to the variable a
It could be the bitwise AND operator
0x53 & 0x0f // Here's a bitwise AND operation, the result is 0x03
You're mistaken by the syntax. This is unhappy, but & is both the addressof operator and the token meaning "referente to".
int &b = a;
This declares the variable b to be of type int& (reference to an int) and initialized to a. No address whatsoever.

Temporary objects in C++

I was going through reference return and came across temporary objects. I don't understand how to identify them. Please explain using this example:
If a and b are objects of same class, consider binary operator+. If you use it in an expression such as f(a+b), then a+b becomes temporary object and f has to of form f(const <class name>&) or f(<class name>). It can't be of form f(<class name>&) However, (a+b).g() is perfectly alright where g() can even change contents of object returned by a+b.
When you say f(a + b), the parameter of f needs to bind to the value with which the function was called, and since that value is an rvalue (being the value of a function call with non-reference return type)*, the parameter type must be a const-lvalue-reference, an rvalue-reference or a non-reference.
By constrast, when you say (a + b).g(), the temporary object is used as the implicit instance argument in the member function call, which does not care about the value category. Mutable values bind to non-const and const member functions, and const values only bind to const member functions (and similarly for volatile).
Actually, C++11 did add a way to qualify the value category of the implicit instance argument, like so:
struct Foo()
{
Foo operator+(Foo const & lhs, Foo const & rhs);
void g() &; // #1, instance must be an lvalue
void g() &&; // #2, instance must be an rvalue
}
Foo a, b;
a.g(); // calls #1
b.g(); // calls #1
(a + b).g(); // calls #2
*) this is the case for an overloaded operator as in this example, and also for built-in binary operators. You can of course make overloaded operators which produce lvalues, though going against the common conventions would probably be considered very confusing.
Your confusion comes not from that you cannot identify temporary objects, in both cases result of a+b is temporary object, but wrong assumption that non const method requires lvalue and would not accept temporary object, which is not true.
For a simple case, think of following piece of code:
int func(int lhs, int rhs)
{
return lhs + rhs;
}
int main() {
int a = 1, b = 2, c = 3;
return func(a * c, b * c);
}
Because func takes two integers, the program must calculate the values of a * c and b * c and store them somewhere -- it can't store them in a or b or c. So the resulting code is equivalent to:
int lhsParam = a * c;
int rhsParam = b * c;
return func(lhsParam, rhsParam);
Again, at the end of func() we return a calculate value, lhs + rhs. The compiler must store it in a new place.
For integers and so forth this seems very simple, but consider instead
int function(std::string filename);
function("hello");
filename has to be a std::string, but you passed a const char*. So what the compiler does is:
std::string filenameParam = "hello"; // construct a new object
function(filenameParam);
just like the previous example, but this time it is hopefully clearer that we're constructing a temporary object.
Note: The convention of calling them "somethingParam" is just for clarity in this answer.

Relevance of const return type in NRVO cases

This is a follow up question from Calling constructor in return statement.
This a operator overload fun in a class.
const Integer operator+(const Integer& IntObject)
{
cout << "Data : " << this->data << endl;
return Integer(this->data + IntObject.data);
}
What is the relevance of const in the return type for such functions?
int main()
{
Integer A(1); //Create 2 object of class Integer
Integer B(2);
const Integer C = A + B; //This will work
Integer D = A + B; //This will also work
fun(A + B); //Will work
}
void fun(Integer F) {}
This is a case temporaries are not created during return step due to NRVO. The object to be returned is directly constructed on the callee's address.
Here's a better example:
struct Foo
{
void gizmo();
Foo const operator+(Foo const & rhs);
};
Now if you have a Foo x; Foo y;, then you cannot say:
(x + y).gizmo(); // error!
The constant return value means you cannot use it for non-constant operations. For primitive types this is not quite so relevant, because there aren't many non-constant operations you can perform on temporary objects, because lots of "interesting" operations (like prefix-++) aren't allowed on temporaries.
That said, with C++11 one should really try and adopt the new idiom of never returning constant values, since non-constant values are now amenable to move optimisations.
Some people used to suggest doing that, to prevent writing nonsense like A + B = C. However, in C++11 it can prevent some optimisations since it makes the return value unmovable. Therefore, you shouldn't do it.
In this case, it also prevents you from writing perfectly valid code like D = A + B + C, but that's just because the author forgot to declare the operator const.
There is no relevance in your code snippet, because you are making a copy of the returned value.
In general, it is difficult to find good reasons to return a const value. I can only see it having an effect in this type of expression, attempting to call a non-const method on a const temporary:
(someObject.someMethodReturningConstValue()).someNonConstMethod(); // error, calls non const method on const temporary
so you should only use it if you want to disallow calling non-const methods on temporaries. On the other hand, it kills move-semantics in C++11 so is discouraged.

In C++, what does & mean after a function's return type?

In a C++ function like this:
int& getNumber();
what does the & mean? Is it different from:
int getNumber();
It's different.
int g_test = 0;
int& getNumberReference()
{
return g_test;
}
int getNumberValue()
{
return g_test;
}
int main()
{
int& n = getNumberReference();
int m = getNumberValue();
n = 10;
cout << g_test << endl; // prints 10
g_test = 0;
m = 10;
cout << g_test << endl; // prints 0
return 0;
}
the getNumberReference() returns a reference, under the hood it's like a pointer that points to an integer variable. Any change applyed to the reference applies to the returned variable.
The getNumberReference() is also a left-value, therefore it can be used like this:
getNumberReference() = 10;
Yes, the int& version returns a reference to an int. The int version returns an int by value.
See the section on references in the C++ FAQ
Yes, it's different.
The & means you return a reference. Otherwise it will return a copy (well, sometimes the compiler optimizes it, but that's not the problem here).
An example is vector. The operator[] returns an &. This allows us to do:
my_vector[2] = 42;
That wouldn't work with a copy.
The difference is that without the & what you get back is a copy of the returned int, suitable for passing into other routines, comparing to stuff, or copying into your own variable.
With the &, what you get back is essentially the variable containing the returned integer. That means you can actually put it on the left-hand side of an assignment, like so:
getNumber() = 200;
The first version allows you to write getNumber() = 42, which is probably not what you want. Returning references is very useful when overloading operator[] for your own containers types. It enables you to write container[9] = 42.
int& getNumber(): function returns an integer by reference.
int getNumber(): function returns an integer by value.
They differ in some ways and one of the interesting differences being that the 1st type can be used on the left side of assignment which is not possible with the 2nd type.
Example:
int global = 1;
int& getNumber() {
return global; // return global by reference.
}
int main() {
cout<<"before "<<global<<endl;
getNumber() = 2; // assign 2 to the return value which is reference.
cout<<"after "<<global<<endl;
return 0;
}
Ouptput:
before 1
after 2
"&" means reference, in this case "reference to an int".
It means that it is a reference type. What's a reference?
Wikipedia:
In the C++ programming language, a reference is a simple reference datatype that is less powerful but safer than the pointer type inherited from C. The name C++ reference may cause confusion, as in computer science a reference is a general concept datatype, with pointers and C++ references being specific reference datatype implementations. The declaration of the form:
Type & Name
where is a type and is
an identifier whose type is reference
to .
Examples:
int A = 5;
int& rA = A;
extern int& rB;
int& foo ();
void bar (int& rP);
class MyClass { int& m_b; /* ... */ };
int funcX() { return 42 ; }; int (&xFunc)() = funcX;
Here, rA and rB are of type "reference
to int", foo() is a function that
returns a reference to int, bar() is a
function with a reference parameter,
which is reference to int, MyClass is
a class with a member which is
reference to int, funcX() is a
function that returns an int, xFunc()
is an alias for funcX.
Rest of the explanation is here
It's a reference
It means it's returning a reference to an int, not an int itself.
It's a reference, which is exactly like a pointer except you don't have to use a pointer-dereference operator (* or ->) with it, the pointer dereferencing is implied.
Especially note that all the lifetime concerns (such as don't return a stack variable by address) still need to be addressed just as if a pointer was used.