I'm doing some exploration of operator-overloading at the moment whilst re-reading some of my old University text-books and I think I'm mis-understanding something, so hopefully this will be some nice easy reputation for some answerers. If this is a duplicate please point me in the right direction.
I've created a simple counter class that has (at this stage) a single member, val (an int).
I have initialised three of these counters, varOne to varThree, and want the third counter to be the sum of the first two (e.g. varThree.val is set to 5 in the below code)
counter::counter(int initialVal)
{
val = initialVal;
//pVal = new int;
//*pVal = 10; // an arbitrary number for now
}
int main (int argc, char const* argv[])
{
counter varOne(3), varTwo(2), varThree;
varThree = varOne + varTwo;
return 0;
}
I've overloaded operator+ like so:
counter operator+(counter& lhs, counter& rhs)
{
counter temp(lhs.val + rhs.val);
return temp;
}
I've made this a non-member function, and a friend of the counter class so that it can access the private values.
My problem starts when adding another private member, pVal (a pointer to an int). Adding this means that I can no longer do a simple varThree = varOne copy because when varOne is destroyed, varThree.pVal will still be pointing to the same bit of memory.
I've overloaded operator= as follows.
int counter::getN()
{
return *newVal;
}
counter& counter::operator=(counter &rhs)
{
if (this == &rhs) return *this;
val = rhs.val;
delete pVal;
pVal = new int;
*pVal = rhs.getN();
return *this;
}
Now if I do something like varThree = varOne everything copies correctly, however trying to do varThree = varOne + varTwo gives me the following error:
counter.cpp: In function ‘int main(int, const char**)’:
counter.cpp:96: error: no match for ‘operator=’ in ‘varThree = operator+(counter&, counter&)(((counter&)(& varTwo)))’
counter.cpp:55: note: candidates are: counter& counter::operator=(counter&)
make: *** [counter] Error 1
It looks as though counter::operator= is having trouble coping with the return output from operator+, and that I need to overload operator= further to accept the type that operator+ is returning, but I've had no luck and I'm beginning to think that maybe I've done something fundamentally wrong.
You need to pass your parameters as const reference. For example:
counter& counter::operator=( const counter &rhs )
And similarly for operator+(). This is necessary in order to be able to bind temporary values to the function parameter(s). Temporary values are created when you return by value, so when you say:
varOne + varTwo
a nameless temporary is created. This is the right thing to do, but you have to make sure that functions such as the assignment op can accept such values by making their parameters const.
You also need to implement the copy constructor and destructor for your class, though lack of these will not cause compilation errors (unfortunately).
Another way to approach this problem is to use the PImpl pattern and swap for the assignment operator. Assuming that you still have a counter(int) constructor you could write operator= as follows
counter& counter::operator=(const counter& rhs) {
counter temp(rhs.getN());
std::swap(&pVal,rhs.pVal);
return *this;
}
This has the benefit of leaving the messy memory management functions in the constructor and destructor where they should be.
The key here (as touched upon by a previous poster) but worth emphasizing is that expressions in C++ can be categorized as being either rvalues or lvalues.
Their is much detail behind those categories, but a useful heuristic to guide your intuition is: if you can take the address of an expression (such as a variable) it is an lvalue (there is much more to the story here, but this is a good place to start).
If it is truly not an lvalue, it is an rvalue - and a useful heuristic for rvalues is that they represent "hidden" temporary objects that the compiler instantiates to make your code work. These objects are created and destroyed by the compiler behind the scenes.
Why is this relevant here?
Well, in C++98/03 (which is what i presume you are using), remember the following two rules:
1) Only lvalue expressions can bind to non-const references (ignoring casts)
2) rvalue expressions can bind to only const references (ignoring casts)
An example will help here:
// Consider the function foo below - it returns an int -
// whenever this function is called, the compiler has
// to behave as if a temporary int object with the value 5 is returned.
// The use of 'foo()' is an expression that is an rvalue - try typing &foo() -
// [Note: if foo was declared as int& foo(), the story gets complicated, so
// i'll leave that for another post if someone asks]
int foo() { return 5; }
void bind_r(int& r) { return; }
void bind_cr(const int& cr) { return; }
int main()
{
int i = 10; // ok
int& ri = i; // ok binding lvalue to non-const reference, see rule #1
int& ri2 = foo(); // Not ok, binding a temporary (rvalue) to a non-const reference
// The temporary int is created & destroyed by compiler here
const int& cri = foo(); // ok - see rule #2, temporary int is NOT destroyed here
//Similarly
bind_r(i); // ok - rule #1
bind_r(foo()); // NOT ok - rule #2
bind_cr(foo()); // ok - rule #2
// Since the rules above keep you out of trouble, but do not exhaust all possibilities
// know that the following is well-formed too:
const int& cri2 = i;
bind_cr(i);
bind_cr(cri);
bind_cr(cri2);
}
When you bind an rvalue to a const reference, you basically extend the temporary object's life-time to the life-time (in this case scope) of the reference (and the compiler can not just destroy it at the end of that expression) - so you end up with a reference to a valid object.
I hope this helps in understanding why you have to declare your assignment operator as accepting a const reference and not just a non-const reference, as one of the other posters rightly recommended.
p.s. There are some other issues with your code (such as why you are destroying and creating the memory that your object exclusively points to upon each assignment, and the lack of a copy constructor and destructor), and if no one has addressed them by the time this post appears, i will :)
p.s. It may also be worth knowing that C++0x adds something known as rvalue references (non-const) that preferentially bind to rvalues and provide for extremely powerful optimization opportunities for the programmer (without having to rely on the optimization capabilities of the compiler) - they also help solve the problem of creating the perfect forwarding function in C++ - but now we're digressing ;)
Related
I'm learning C++ and pointers and I thought I understood pointers until I saw this.
On one side the asterix(*) operator is dereferecing, which means it returns the value in the address the value is pointing to, and that the ampersand (&) operator is the opposite, and returns the address of where the value is stored in memory.
Reading now about assignment overloading, it says "we return *this because we want to return a reference to the object". Though from what I read *this actually returns the value of this, and actually &this logically should be returned if we want to return a reference to the object.
How does this add up? I guess I'm missing something here because I didn't find this question asked elsewhere, but the explanation seems like the complete opposite of what should be, regarding the logic of * to dereference, & get a reference.
For example here:
struct A {
A& operator=(const A&) {
cout << "A::operator=(const A&)" << endl;
return *this;
}
};
this is a pointer that keeps the address of the current object. So dereferencing the pointer like *this you will get the lvalue of the current object itself. And the return type of the copy assignment operator of the presented class is A&. So returning the expression *this you are returning a reference to the current object.
According to the C++ 17 Standard (8.1.2 This)
1 The keyword this names a pointer to the object for which a
non-static member function (12.2.2.1) is invoked or a non-static data
member’s initializer (12.2) is evaluated.
Consider the following code snippet as an simplified example.
int x = 10;
int *this_x = &x;
Now to return a reference to the object you need to use the expression *this_x as for example
std::cout << *this_x << '\n';
& has multiple meanings depending on the context. In C and used alone, I can either be a bitwise AND operator or the address of something referenced by a symbol.
In C++, after a type name, it also means that what follows is a reference to an object of this type.
This means that is you enter :
int a = 0;
int & b = a;
… b will become de facto an alias of a.
In your example, operator= is made to return an object of type A (not a pointer onto it). This will be seen this way by uppers functions, but what will actually be returned is an existing object, more specifically the instance of the class of which this member function has been called.
Yes, *this is (the value of?) the current object. But the pointer to the current object is this, not &this.
&this, if it was legal, would be a pointer-to-pointer to the current object. But it's illegal, since this (the pointer itself) is a temporary object, and you can't take addresses of those with &.
It would make more sense to ask why we don't do return this;.
The answer is: forming a pointer requires &, but forming a reference doesn't. Compare:
int x = 42;
int *ptr = &x;
int &ref = x;
So, similarly:
int *f1() return {return &x;}
int &f1() return {return x;}
A simple mnemonic you can use is that the * and & operators match the type syntax of the thing you're converting from, not the thing you're converting to:
* converts a foo* to a foo&
& converts a foo& to a foo*
In expressions, there's no meaningful difference between foo and foo&, so I could have said that * converts foo* to foo, but the version above is easier to remember.
C++ inherited its type syntax from C, and C type syntax named types after the expression syntax for using them, not the syntax for creating them. Arrays are written foo x[...] because you use them by accessing an element, and pointers are written foo *x because you use them by dereferencing them. Pointers to arrays are written foo (*x)[...] because you use them by dereferencing them and then accessing an element, while arrays of pointers are written foo *x[...] because you use them by accessing an element and then dereferencing it. People don't like the syntax, but it's consistent.
References were added later, and break the consistency, because there isn't any syntax for using a reference that differs from using the referenced object "directly". As a result, you shouldn't try to make sense of the type syntax for references. It just is.
The reason this is a pointer is also purely historical: this was added to C++ before references were. But since it is a pointer, and you need a reference, you have to use * to get rid of the *.
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.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What does T&& mean in C++11?
For some reason, this is eluding my intuition, and I cannot find any explanation on the internet. What does it mean for a C++ function to take a reference of a reference? For example:
void myFunction(int&& val); //what does this mean?!
I understand the idea of passing-by-reference, so
void addTwo(int& a)
{
a += 2;
}
int main()
{
int x = 5;
addTwo(x);
return 0;
}
works and is intuitive to me.
This is not a reference of a reference, but rather a new language feature called an rvalue reference that represents (informally) a reference to an object in memory that isn't referenced elsewhere in the program and can be destructively modified. For example, the return value of a function can be captured by an rvalue reference, as can temporary values introduced into expressions.
Rvalue references can be used for a variety of purposes. From the perspective of most C++ programmers, they can be used to implement move semantics, whereby a new object can be initialized by "moving" the contents of an old object out of the old object and into a new object. You can use this to return huge objects from functions in C++11 without paying a huge cost to copy the object, since the object used to capture the return value can be initialized using the move constructor by just stealing the internals from the temporary object created by the return statement.
Move semantics are orthogonal to copy semantics, so objects can be movable without being copyable. For example, std::ofstreams are not copyable, but they will be movable, so you could return std::ofstreams from functions using the move behavior. This currently cannot be done in C++03. For example, this code is illegal in C++03 but perfectly fine (and encouraged!) in C++11:
std::ifstream GetUserFile() {
while (true) {
std::cout << "Enter filename: ";
std::string filename;
std::getline(std::cin, filename);
ifstream input(filename); // Note: No .c_str() either!
if (input) return input;
std::cout << "Sorry, I couldn't open that file." << std::endl;
}
}
std::ifstream file = GetUserFile(); // Okay, move stream out of the function.
Intuitively, a function that takes an rvalue reference is a function that (probably) is trying to avoid an expensive copy by moving the contents of an old object into a new object. For example, you could define a move constructor for a vector-like object by having that constructor take in an rvalue reference. If we represent the vector as a triple of a pointer to an array, the capacity of the array, and the used space, we might implement its move constructor as follows:
vector::vector(vector&& rhs) {
/* Steal resources from rhs. */
elems = rhs.elems;
size = rhs.size;
capacity = rhs.capacity;
/* Destructively modify rhs to avoid having two objects sharing
* an underlying array.
*/
rhs.elems = nullptr; // Note use of nullptr instead of NULL
rhs.size = 0;
rhs.capacity = 0;
}
It's important to notice that when we clear out rhs at the end of the constructor that we end up putting rhs into such a state that
Will not cause a crash when its destructor invokes (notice that we set its element pointer to nullptr, since freeing nullptr is safe), and
Still lets the object be assigned a new value. This latter point is tricky, but it's important to ensure that you can still give the cleared-out object a new value at some point. This is because it is possible to obtain an rvalue reference to an object that can still be referenced later in the program.
To shed some light on (2), one interesting use case for rvalue references is the ability to explicitly move values around between objects. For example, consider this idiomatic implementation of swap:
template <typename T> void swap(T& lhs, T& rhs) {
T temp = lhs;
lhs = rhs;
rhs = temp;
}
This code is legal, but it's a bit unusual. In particular, it ends up making three copies - first when setting temp equal to a copy of lhs, once setting lhs to be a copy of rhs, and once setting rhs to be a copy of temp. But we don't really want to be making any copies at all here; instead, we just want to shuffle the values around. Consequently, in C++11, you'll be able to explicitly get rvalue references to objects by using the std::move function:
template <typename T> void swap(T& lhs, T& rhs) {
T temp = std::move(lhs);
lhs = std::move(rhs);
rhs = std::move(temp);
}
Now, no copies are made at all. We move the contents of lhs into temp, then move the contents of rhs into lhs, then moves the contents of temp into rhs. In doing so, we left both lhs and rhs in an "emptied" state temporarily before putting new values into them. It's important that when writing the code to move the contents out of an object that we leave the object in a somewhat well-formed state so that this code works correctly.
It's not a reference to a reference. It's a new syntax introduced in C++0x for so-called Rvalue references.
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).
is the following code safe (it works in DEBUG) :
void takesPointer(const Type* v);//this function does read from v, it doesn't alter v in any way
Type getValue();
...
takesPointer(&getValue());//gives warning while compiling "not an lvalue"
...
Type tmp = getValue();
takesPointer(&tmp);//this is safe, and maybe I should just do it, instead of posting here
so - is it safe ? should I just forget about it and use the code with the explicit tmp ?
but anyways - I'm still interested if the optimizer is allowed to kill the temporary before returning from this call :
takePointer(&getValue())
EDIT:
thank you all !
unfortunately I can't change the function "takesPointer" (it's part of a library), I could only wrap it in a function "takesReference", which calls takesPointer - would this eliminate the copy, or would the compiler still be allowed to create a copy (the "Type" is a int-3x3-Matrix, so it wouldn't be THAT bad, but still...) ?
inline void takesReference(const Type& v){ takesPointer(&v); }
About the time of destruction : will it be destroyed after "takesPointer" RETURNS, or after it's CALLED ?
As other answers have stated you cannot take the address of a temporary. However, if you change the signature of
void takesPointer(const Type* v);
to
void takesPointer(const Type& v);
then the following code should compile without warnings:
takesPointer(getValue());
because you are allowed to bind a temporary to a const reference, and it should work just the same.
The Standard forbids you to do &getValue() - exactly because it's not an lvalue. Ordinarily, if this was allowed, then the temporary resulting from that function call will live until the outer function returns and every other thing in the whole expression has completed being processed. This can be called "destroying temporaries after end of full-expression", and ensures things like the following works as expected
// the temporary string is alive until the whole expression has been processed
cout << string("hello");
The compiler gives you a diagnostic - that's all the Standard requires for ill-formed code. It doesn't force the compiler to abort compilation, for instance. But after code being ill-formed was diagnosed, the compiler can do everything it wants. So if you want to know what the compiler does in your case, you should read its manual.
This will prevent copies* and compiles.
const Type& tmp = getValue();
takesPointer(&tmp);
Prevent copies is a bit strong because the compiler will often do this for you.
You have to have access to the copy constructor but the compiler will often not use it:
#include "iostream"
class Type
{
public:
explicit Type(int val) : m_val(val) { std::cout << "ctor";};
Type(const Type& copy)
{
std::cout << "copy";
};
private:
int m_val;
};
Type getValue() { Type r(0); return r;};
void takesPointer(const Type* const)
{
};
int main(int argc, char* argv[])
{
const Type tmp = getValue();
takesPointer(&tmp);
}
Will print only "ctor" in release and "ctorcopy" in debug. (MVS2005)
You are allowed to bind a non-const rvalue to a const reference lvalue, but you're binding it to a const pointer lvalue.
And no, the optimzier can't destruct the result of getValue() before calling takePointer().
Yes, it is safe, albeit illegal in the current form. You can work around the error by using an explicit intermediate cast to const-reference type
takesPointer( &(const Type &) getValue() );
This makes it perfectly legal as long as the temporary object is alive, which is till the end of evaluation of the full expression.
Moreover, you can even cast away the constness and modify the temporary object through the pointer (keeping in mind that it will be destroyed at the end of full expression). This is perfectly legal as long as the temporary object itself is not constant.
Using a comma operator, you can "stretch" full expressions, and thus write quite extensive sequences of operations that work with a "long-lived" temporary object
Type *p;
p = &(Type &) (const Type &) getValue(), modify(p), print(p), modifyAgain(p), print(p);
// Not using C++ casts for brevity
The practice is rather questionable though and most of the time there's no point in doing this.