How overloaded postfix operator works? - c++

I have the following code:
class Array
{
public:
int aaa;
Array():aaa(1){}
void print()
{
cout << aaa << endl;
}
Array& operator++()
{
aaa++;
return *this;
}
Array operator++(int)
{
Array a(*this);
aaa++;
return a;
}
};
I have some questions as follows:
why prefix returns a reference and postfix returns an object? In the book C++ Primer, the author only explained "For consistency with the built-in operators".
Then, I tested the code:
Array ar;
(ar++).print(); // print 1
ar.print(); // print 2
the output is exactly what I expected.
Now I changed the code in the overloading postfix function as:
Array operator++(int)
{
Array a(*this);
a.aaa++; // changed this
return a;
}
I called the test code:
Array ar;
(ar++).print(); // this prints 2
ar.print(); // this prints 1
Why I got such results?

The postfix operator returns an object, not a reference, because it has to return an unchanged version of the current object; it has to return the value before the increment is done. Therefore a new object must be allocated. If you returned a reference, what would it be a reference to?
In your second example, you're creating a new object, incrementing it, and returning it, but you're not changing the original object that the operator was applied to -- this is clearly wrong, so gives wrong results.

While both prefix and postfix operators would intuitively seem to mutate the objects on which they're invoked, they actually have different semantic meanings. The prefix operator takes an an object, applies the increment operation to it, and returns the same object. The postfix operator takes an object, makes a copy of it, applies the increment operator to the orginal, and returns the copy.
It's for this reason that you may have seen various sources discouraging the use of the postfix operator when possible -- because the postfix copy creates a temporary object, it may be less efficient than the prefix operator. For an object that has to maintain a lot of state information, using the postfix operator can be expensive.

Related

How does the syntax for overloading post-increment operator in c++ work?

int operator++(int){
//relevant code
}
I dont seem to understand the workings of the code for overloading post increment operator given
above
I know that the int as a dummy parameter is given to differentiate between pre-increment and post increment operator overloading.
If a is a object of the class in which these operators are overloaded ,both ++a and a++ should have a equivalent representation as a.operator++()(as per my understanding ),how does the int parameter help in resolving it as a post increment operator?
-A c++ beginner
If a is a object of the class in which these operators are overloaded
,both ++a and a++ should have a equivalent representation as
a.operator++()(as per my understanding ),how does the int parameter
help in resolving it as a post increment operator?
The post increment operator can be called with a dummy int argument but normally this isn't what you would do. In the following, typically you would define void foo::operator++(int) so that you can make a call like (1) but (2) is legal.
#include<iostream>
struct foo {
void operator++() {
std::cout << "pre\n";
}
void operator++(int) {
std::cout << "post\n";
}
};
int main() {
foo a;
// these yield: pre
++a;
a.operator++();
// these yield post:
a++; // (1)
a.operator++(int{}); // (2)
}
When the compiler sees ++a, and a is not a built-in type, then the compiler looks for either a::operator++() or operator++(a&) and if found then calls it.
When the compiler sees a++, and a is not a built-in type, then the compiler looks for either a::operator++(int) or operator++(a&, int) and if found then calls it.
See Increment/decrement operators on cppreference.com for more details.

Why do we return *this in asignment operator and generally (and not &this) when we want to return a reference to the object?

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 *.

c++ operator += overloading return reference to

Could somebody explain what the difference is in this example of operator overloading, Average& operator+=(int num) where you return a reference to Average versus not returning a reference to Average i.e. Average operator+=(int num).
Does returning a reference mean return a reference to the object being assigned to (not a copy) which is *this. So in this case return a reference to the object avg.
How/why does the non reference version work? Where is the result being copied?
#include <iostream>
#include <cstdint> // for fixed width integers
class Average
{
private:
int32_t m_total = 0; // the sum of all numbers we've seen so far
int8_t m_numbers = 0; // the count of numbers we've seen so far
public:
Average()
{
}
friend std::ostream& operator<<(std::ostream &out, const Average &average)
{
// Our average is the sum of the numbers we've seen divided by the count of the numbers we've seen
// We need to remember to do a floating point division here, not an integer division
out << static_cast<double>(average.m_total) / average.m_numbers;
return out;
}
// Because operator+= modifies its left operand, we'll write it as a member
Average& operator+=(int num)
{
// Increment our total by the new number
m_total += num;
// And increase the count by 1
++m_numbers;
// return *this in case someone wants to chain +='s together
return *this;
}
};
int main()
{
Average avg;
avg += 4;
std::cout << avg << '\n';
return 0;
}
You should return a reference because thats a convention most code in standard library is using, and most programmers do. Most programmers will expect below code:
std::string s;
(s += "a") = "b";
std::cout << s << std::endl;
to print b, or in this example:
int n = 10;
(n += 20) = 100;
std::cout << n << std::endl;
will expect 100 to be printed.
That is why you should return a reference to keep with the convention which allows to modify object which is on the left side of assignment.
Otherwise, if you return by value (a copy) assignment as in above examples will assign to a temporary.
When overriding operators in C++, one can provide them in multiple forms. You can define assignment operators which do not return a reference to the modified object, and they would work as expected. But, we have for each operator what we call a canonical implementation:
Other than the restrictions above, the language puts no other constraints on what the overloaded operators do, or on the return type (it does not participate in overload resolution), but in general, overloaded operators are expected to behave as similar as possible to the built-in operators: operator+ is expected to add, rather than multiply its arguments, operator= is expected to assign, etc. The related operators are expected to behave similarly (operator+ and operator+= do the same addition-like operation). The return types are limited by the expressions in which the operator is expected to be used: for example, assignment operators return by reference to make it possible to write a = b = c = d, because the built-in operators allow that.
Commonly overloaded operators have the following typical, canonical forms.
There is a lot to read about those canonical forms, but I'd suggest to start with this really good SO answer on What are the basic rules and idioms for operator overloading?
How/why does the non reference version work?
Because even if the C++ Standard encourages you to use the canonical forms, it doesn't forbid you not to.
Where is the result being copied?
Nowhere, the value is discarded. Implementation will probably optimize them away.
Does returning a reference mean return a reference to the object being assigned to (not a copy) which is *this. So in this case return a reference to the object avg.
Yes.
How/why does the non reference version work? Where is the result being copied?
The returned value is a temporary object that is passed to std::cout <<.
It's similar to using:
int foo()
{
return 10;
}
std::cout << foo() << std::endl;
The return value of foo is a temporary object that is passed to std::cout <<.
Try to check this similar question.
When you return reference, you are actually passing the actual object. While when you return by value, temporary object is created and then passed to caller.
So if you return without reference this assignment may work as per your code segment above.
Average aa = avg += 4;
But it will fail to compile if you try.
Average *ptr = &(avg += 4);
The above code will work if you return reference though, since we are passing valid scope of object.

Postfix increment operator

I have a custom class MyInt, encapsulating a int m_nValue data. The postfix operator
MyInt operator++(int)
{
MyInt temp(*this);
++(*this);
return temp;
}
if the operator returns an object, then why i am not able to call postfix++ operator more than once like:
MyInt value(10);
value++; // valid
value++++; // Why is this invalid?? Cant it be interpreted as (value++)++
Why does value++++ gives an error lvalue required
if i can call value.print() method defined in MyInt Class, then i should also be able to do value++++?
Wrong answer:
Because value++ is a temporary variable that holds the old value of value. You can't ++ it.
You also can't write 15++! It's similar. The former is a temporary variable, the later is a constant, none of which you can increment.
Correction: Since this answer got accepted, I am not going to change the original post, but since people will read it, I will post the correction here.
First off, I am not saying constants and temporary objects are the same concept. I was just trying to say temporary objects are not l-values, like constants are not, without actually using the word l-value.
About value++++, it is not an error. I just tested it with my g++ 4.5 and it works fine. In other answers you can read:
From section 3.10.10 of the 2003 standard:
An lvalue for an object is necessary in order to modify the object except that an rvalue of class type can also be used to modify its referent under certain circumstances. [Example: a member function called for an object (9.3) can modify the object. ]
What is inherently wrong about what you are doing is this:
Let's say value holds 10. The first value++ changes value to 11 but returns a temporary object containing 10. Then you ++ it which changes the temporary value (that you never access) to 11, but again returns a temporary object that contains 10. So value++++ behaves exactly like value++ except it does some unnecessary work.
Actually, this should work:
#include <iostream>
struct MyInt {
MyInt() : value(0) {}
MyInt& operator++() {
std::cout << "Inside MyInt::operator++()" << std::endl;
++value;
return *this;
}
MyInt operator++(int)
{
MyInt temp(*this);
++(*this);
return temp;
}
int value;
};
int main() {
MyInt mi;
std::cout << "Value before: " << mi.value << std::endl;
mi++++;
std::cout << "Value after: " << mi.value << std::endl;
}
This operator is basically just a normal member-function with fancy syntax, and as such you can invoke it on an rvalue. Note how, as Martinho explains in his comment, the effect is not the desired one, because the second increment operates on a temporary.
From section 3.10.10 of the 2003 standard:
An lvalue for an object is necessary in order to modify the object
except that an rvalue of class type can also be used to modify its
referent under certain circumstances. [Example: a member function
called for an object (9.3) can modify the object. ]

Is operator-> "chained" for pointers? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Overloading operator ->
Hi,
I've seen that operator->() is chained (re-applied) after it is evaluated, for example:
struct Bar
{
Bar() : m_str("Hello world!") {}
const string* operator->() const { return &m_str; }
string m_str;
};
struct Foo
{
const Bar& operator->() const { return m_bar; }
Bar m_bar;
};
int main()
{
Foo f;
cout << f->c_str() << endl;
return 0;
}
works pretty fine, which requires three operator->() to be evaluated - Foo::operator->(), Bar::operator->() and regular pointer resolution.
But it wont work with pointers in the middle - if Foo::operator->() returns pointer to Bar instead of reference, it wont compile. Same happens with auto_ptr<auto_ptr<string>> for example.
Is it specific to non-overloaded operator->() so it is only applied once and does not cause chaining?
Is it possible to make code below works without using (*ptr2)-> ...?
int main()
{
string s = "Hello world";
auto_ptr<string> ptr1(&s);
auto_ptr<auto_ptr<string> > ptr2(&ptr1);
cout << ptr1->c_str() << endl; // fine
cout << ptr2->c_str() << endl; // breaks compilation
}
Thanks!
C++98 standard §13.5.6/1 "Class member access":
An expression x->m is interpreted as (x.operator->())->m for a class object x of type T if T::operator-> exists and if the operator is selected at the best match function by the overload resolution mechanism (13.3).
What this means in practice is that when x is a pointer, you don’t get chaining; you then just get the built-in operator-> (i.e. x->m with x a pointer translates to (*x).m).
But when x is an object of class type T, then you can get the chaining effect. Because then the interpretation as (x.operator->())->m can be that (x.operator->()) itself is an object of some class, say class U. Whence the second -> can be resolved as U::operator->, and so on, if the result of that again is a class type object…
Like, in your case, Foo::operator-> produces (a reference to) an object of class Bar, which does define an operator->.
But when operator-> returns a pointer, as e.g. std::auto_ptr<T>::operator-> does, then it's just the built-in operator-> that's used.
In passing, the chaining can be used to practically prevent someone from using delete inappropriately. std::auto_ptr does not do that. And I’ve never seen it done.
But there was once a long discussion thread over in [comp.lang.c++.moderated] about how to prevent inadvertent delete of the raw pointer managed by a smart pointer, and this was one possibility that was discussed.
Cheers & hth.
The reason your first example works is because you returned a reference instead of a pointer. That operator would normally be invalid except in the case that it is overloaded. Therefore, the compiler must execute the overloaded functions down the chain. However, in the case of auto_ptr you actually are returned a real pointer and the default operator -> is invoked for regular pointers.
Please see the Overloading operator -> question for more details.
No, it is not possible for it to work. If you could overload operator -> for string * you could make it work. But operator -> already has a definition for all pointer types. So, just like you can't overload + for primitive numeric types, you can't overload operator -> for any pointer type.
And even if you could, how could the compiler know when the recursion should end?