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.
Related
I need to add optional parameters to the end of most function calls in my program. Right now the function's parameters look along the lines of
foo(int a, char b, const unique_ptr c)
What I've added is a default value for the last parameter to make it optional so it looks like
foo(int a, char b, const unique_ptr c = NULL)
Can a const variable be assigned in the parameters as I've done? Or does this go against the nature of constant variables?
Variables that are qualified as const can be initialized, but not altered (e.g. assigned to) afterwards. This is true for any ordinary variable as well as a function parameter. Lets simplify your example to
void foo(const int a = 1) {}
This in itself is a valid function signature, it tells the compiler that the parameter a is not modified within the function body. This will hence not compile:
void illegalFoo(const int a = 1) { a = 2; /* Error, won't compile */ }
If the calling code passes a value to the function
foo(3);
the function parameter a is initialized to 3 in this example, but again, not changed in the function body. The same reasoning is true for a std::unique_ptr argument:
void foo(const std::unique_ptr<SomeClass> ptr = nullptr)
{
/* No way to alter ptr here */
}
Note, however, that this function signature makes little sense. Passing std::unique_ptr by value means transferring ownership, but a const-qualified instance cannot be cast to an rvalue-reference for the sake of move-constructing another owning smart pointer from it. If no ownership semantics shall be associated with such a function, pass a raw pointer - it can equally well be declared const and defaulted to nullptr.
What you want to do is overload your function, instead of adding a default value for the parameter within its original definition. Overloading a function looks like this:
void foo(int a, int b) {
// this is the original definition, takes 2 parameters, so we initialize c to 0:
const int c = 0;
return a + b;
}
// then, right underneath, you add an overloaded definition for the function:
void foo(int a, int b, const int c) {
// this is the overloaded definition, takes 3 parameters
return a + b + c;
}
This way, the parameter c is entirely optional, when you call foo().
There's nothing wrong with what you've done.
Bear in mind that this syntax:
foo(int a, char b, const unique_ptr c = NULL);
Is basically just syntactical sugar for this:
foo(int a, char b, const unique_ptr c);
foo(int a, char b) {
foo(a, b, NULL);
}
Which is obviously valid and legal, with the proviso that, while it's technically allowed to assign nullptr or NULL to a std::unique_ptr, this is probably bad practice since you're not otherwise allowed to assign raw pointers directly to a smart pointer (i.e. std::unique_ptr<int> ptr = new int(5); will not compile).
It's probably better to write it like this:
foo(int a, char b, const unique_ptr c = {});
This is a code for adding 3 objects of class Integer
#include <iostream>
using namespace std;
class Integer
{
int value;
public:
Integer(int i)
{
value = i;
};
int getValue()
{
return value;
}
friend Integer operator+(const Integer & a,const Integer & b)
{
Integer i(a.value+b.value);
return i;
}
};
int main()
{
Integer a(1), b(2), c(3);
Integer d = a + b + c; //****HERE****
cout << d.getValue() << endl;
return 0;
}
Can someone please explain why const is added to parameters in this case. If I remove const, during compilation I get invalid operands to binary operation error.
Adding to this question:
When I only add a and b without const, output is 3 without any errors. However, adding 3 a+b+c objects, I get an error. Why is that?
Let's say hypothetically we had written this function:
friend Integer operator+(Integer& a, Integer& b);
Stylistically, this isn't great because operator+ shouldn't be modifying its arguments. But let's say we don't care about that. Now, what happens when we try to do this:
Integer d = a + b + c;
This is grouped as (a+b)+c. The a+b subexpression will find our operator+(), which is a viable function because a and b are non-const lvalues of type Integer, and the result of that expression is an rvalue of type Integer.
The subsequent expression is {some rvalue Integer} + c. That expression we won't be able to find a viable function for. While c can bind to Integer&, the first argument cannot - you can't bind an rvalue to a non-const lvalue reference. So you'd have to write something like:
Integer tmp = a + b; // OK
Integer d = tmp + c; // also OK
but now we're introducing this extra name into our scope and an extra statement into our code just to get around the unviability of our function signature.
Because you're trying to bind a Temporary to a [non-const-]reference, which isn't allowed in C++.
In the code Integer d = a + b + c;, a + b is evaluated first, and creates a new temporary object which then gets evaluated against c. So the code then becomes Integer d = t<a+b> + c;. Because the first object is now a temporary, only three function signatures will accept it as a parameter: const Integer &, Integer, and Integer &&. The second is not advised because it will create a copy of the object (though, sometimes that's what you want!), and the latter isn't advised because it will refuse to accept persistent objects. The first option, then, is best, because it will accept any Integer object regardless of whether it's expiring or not.
Recommended Reading: What are rvalues, lvalues, xvalues, glvalues, and prvalues? It's very verbose, and will probably require several passes before you "get" it, but it's extremely valuable knowledge for any C++ programmer.
I read it from 'Data Structures and Algorithm Analysis in C++'. The return type of the member function operator= is const Vector&. I wonder if the vector can be modified later?
C++ Primer says we can not change a const reference, it gives this example:
const string& shorterString(const string& s1 , const string& s2)
shorterString("hi","bye") = "X" //wrong
Usually operator= returns a non-const reference to the caller. You can see this in classes from STL, for example.
However, the return type rarely matters, because to return something from assignment is an additional effect which, for example, allows chaining:
a = (b = (c = d));
(a = b).callMethod();
operator= could be void as well, and assignment expressions couldn't be used somewhere else. But they would still work, modify its argument and leave it modifiable, i.e. non-const:
A a, b, c;
b = c; //call, say, void A::operator=(const A &)
a = b; //ditto
//a = b = c; //impossible here
a = c; //works
So, the modification of a has nothing to do with the return type of the assignment operator, but with its side-effects.
As for your second example, shorterString which gets two const-references and returns one of them, should obviously leave it const. And if you need to work with the result in a non-const way, you must use non-const arguments as well: string& shorterString(string& s1, string& s2). These two functions can be overloads, and the compiler will choose an appropriate one.
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.
I have just started C++ and have come across references and have not understood completely.
References , as i read is an alternative name for an object.Why use that instead of directly accessing the object as any operation on references is directly reflected on the object ...?
Why and when are they used ?
Is ist like a constant pointer that is referenced each time it is used ... ?
And , it says
double& dr = 1; ---- says it is an error (some lavalue needed)
const double& cdr = 1; ---- says it is ok.
i dont understand it properly..So please explain why it is so ...
Thank You...:)
Why use that instead of directly
accessing the object as any operation
on references is directly reflected on
the object ...?
C++ passes parameters by value, meaning if you have a function such as:
void foo(MyObject o) { ... }
By default C++ will make a copy of a MyObject, not directly use the object being passed in. So, one use of references is to ensure you are working on the same object:
void foo(MyObject &o) { ...}
Or, if you aren't modifying o:
void foo(const MyObject &o) { ... }
References are another way of what was originally in C code like this
void fubarSquare(int *x){
int y = *x;
*x = y * y;
}
// typical invocation
int z = 2;
fubarSquare(&z);
// now z is 4
with references in C++ it would be like this
void fubarSquareCpp(int& x){
x = x * x;
}
// typical invocation
int z = 2;
fubarSquareCpp(z);
// now z is 4
It's a neater syntactical way of using a call-by-reference parameter instead of using the C's notation asterisk/star to indicate a pointer and as a call-by-reference parameter...and modifying the parameter directly outside of the function...
Have a look at Bjarne Stoustrap's page here which covers how C++ is and also here on the technical faq here
A reference is basically a pointer that looks like an object. It is very very hard to get a NULL reference though you can go through hoops and create one.
With regards to your example, 1 is an rvalue or a result. It is just a temporary variable and can not be modified. Thus you can't take a non const reference to it. However you can take a const reference to it. This means you can't change the value of the reference.
Here is an example of creating a NULL reference. Don't do it!
int * x = (int *)NULL;
int & y = *x;
I agree with you. using references as just an alias name is not very useful.
It is more useful if you consider it as an immutable pointer. But not that useful in fact.
Practically, it is used to define clean interfaces. For example when you define:
int foo(const int& param);
You say that param is a read-only parameter in foo.
Do not forget that you MUST assign a value to a reference.
See the C++ faqlite on references for more
my2c
References improve the syntax, so no pointer dereference needed.
Assuming Base is a class that may be derived from:
void someFunction(Base b)
{
b.function();
// b is a copy of what was passed - probably performance issues
// possible unintended object slicing - you only get the Base part of it
// no virtual function call
// no changes to b visible outside the function
}
void someFunction(Base* b)
{
b->function();
// a shortcut for (*b).function();
// b is the same object that was passed to the function
// possible virtual call
// changes visible outside the function
}
void someFunction(Base& b)
{
b.function();
// b is the same object that was passed to the function
// possible virtual call
// changes visible outside the function
}
References are like constant pointers (NOT pointers to constants - i.e. you can change the object, but you can't change to what you're pointing). const reference is a reference through which you can do things that can be done on const object.
References are also good, because you can't have a null reference
Give the wikipedia article a good read through. To sum it up, references are more friendly version of pointers which are commonly used to pass objects as references into functions without worrying about a null pointer.
To explain the example:
Think of the number 1 represented as a variable. When compiled, this number is put into the global section of the memory which can be referenced by the program, but not modified.
So it is of type: const int
double &dr = 1 is trying to assign dr (a reference to a double) to the const int 1. Since 1 is a constant, the compiler will not allow you to make a non-constant reference to it.
In the second line:
const double &dr = 1 is trying to assign dr (a constant reference to a double) the const int 1. This works because the reference is also const and therefore can point to a const int.
EDIT
The const int is converted to a const double before assigned.
References are language entitities that represent another object they refer to. Nonconst references are lvalues, and must be initialized with an lvalue. They can be useful like this:
int& x=condition ? array[1] : array[2];
int& y=condition ? array[0] : array[3];
x+=y;
y=0;
When used as a function parameter, they tell the caller he has to pass an lvalue that might be written to by the function:
void set1(int& x) { x=1; }
int foo;
set1(foo); // ok, foo is 1
set1(foo+1); // not OK, not lvalue
Const references, on the other hand, can be bound to rvalues. In function parameters, they are usually used to avoid excessive copies:
void niceness(std::string s); // the string would be copied by its copy-ctor
void niceness(const std::string& s); // the caller's string would be used
Note that this may or may not yield faster code.
When const-references are used in normal code, they can bind rvalues, too, and as a special rule, they extend the lifetime of the object they are bound to. This is what you saw in your code:
const double& d=1; // OK, bind a rvalue to a const-ref
double& d=1; // Bad, need lvalue
All references are polymorphic, like pointers:
class A { virtual void f(); }
class B : public A { void f(); }
B b;
A& ar=b;
ar.f(); // calls B::f()
and all references are aliases like pointers:
int f(int& a, const int& b)
{
a=1;
return b;
}
int x;
f(x, 42); // ==42, foo=1
x=42;
f(x, x); // ==1 (not 42), foo=1
double& dr = 1; // 1.0 would be more clear
Is invalid because 1 is viewed to be of type const double so if you want a reference to that variable you need to have a reference to a const double so
const double& dr = 1.0;
Is correct.
Utility of references is most visible in the context of passing parameters to functions.
I.e,
int a;
func definition: void foo (int& param) {param = 1;}
func call: foo(a);
The way as 'param' aliases 'a' is clean and its intention is easily understood by a reader of this code as well as compiler that may optimize away when inlining any additional memory allocation needed for the reference.
Passing a reference to a function and then having the function use the reference is almost like passing a pointer to the function and then having the function dereference the pointer. In many cases, the machine-code implementation will be identical. There are some differences, though, especially in the case of functions that get expanded inline. If a variable is passed by reference to an inline function, the compiler will often be able to substitute the variable itself--even if stored in a machine register--when expanding the function. By contrast, if one takes the address of a variable and passes that as a pointer to a function which then dereferences it, the compiler is less likely to figure out that optimization unless it determines not only that--at least for one particular expansion of the function--the pointer will always point to that variable, but also that the pointer will not be used anywhere else (if the pointer was used elsewhere, the variable could not be kept in a register).