post increment not post

R

Robert Swan

I'd like to know why the following program outputs 1, and not 0.

#include <iostream>

class a {
int v;
public:
a():v(0){}
a& operator++(int) {
v++;
}
operator int&() {
return v;
}
};

int main() {
a aa;
// I intend b to initialize b with 0, then increment a
int b = aa++;
std::cout << b << std::endl;
// didn't happen
}

Thanks,
Robert
 
V

Victor Bazarov

Robert said:
I'd like to know why the following program outputs 1, and not 0.

I am surprised it outputs anything. It's not supposed to compile.
#include <iostream>

class a {
int v;
public:
a():v(0){}
a& operator++(int) {
v++;

This function is defined to have no 'return' statement although one
is required for non-void function which is not a c-tor or d-tor.
It is unknown what you _intended_ to do. The program is ill-formed.
}
operator int&() {
return v;
}
};

int main() {
a aa;
// I intend b to initialize b with 0, then increment a
int b = aa++;
std::cout << b << std::endl;
// didn't happen
}

You need to do something about the operator++, then we can talk.

V
 
R

Robert Swan

Victor Bazarov wrote:
....
I am surprised it outputs anything. It's not supposed to compile.

It did. However, if I had enabled warnings the compiler would have
revealed the inept code.
This function is defined to have no 'return' statement although one
is required for non-void function which is not a c-tor or d-tor.
It is unknown what you _intended_ to do. The program is ill-formed.

Oops. I intended to define class a's post operator ++ to increment
member v, then return a reference to the "invokee object" (not sure what
you're supposed to call it).

I was then thinking the statement

int b = aa++;

should be equivalent to

b = aa; a++;

Seems that it's not.

#include <iostream>

class a {
int v;
public:
a():v(0){}
a& operator++(int) {
v++;
return *this;
}
operator int&() {
return v;
}
};

int main() {
a aa;
// I intend to initialize b with 0, then increment a
int b = aa++;
std::cout << b << std::endl;
// didn't happen
}
 
R

Ron Natalie

Robert said:
I'd like to know why the following program outputs 1, and not 0.

#include <iostream>

class a {
int v;
public:
a():v(0){}
a& operator++(int) {
v++;

You're missing a return here.
If you return
*this
then, the program should behave like you observed.
The v member is incremented and the side effect applied
before the operator++ returns.

If you want it to behave like a real postincrement, you
need to return a copy of the old object.

a operator++(int) {
a temp(*this);
v++;
return a;
}
 
V

Victor Bazarov

Robert said:
Victor Bazarov wrote:
...



It did. However, if I had enabled warnings the compiler would have
revealed the inept code.

I am not sure what 'inept' is in this case. If your compiler allows
the code to compile, the compiler is non-compliant.
Oops. I intended to define class a's post operator ++ to increment
member v, then return a reference to the "invokee object" (not sure what
you're supposed to call it).

We call it (*this).
I was then thinking the statement

int b = aa++;

should be equivalent to

b = aa; a++;

Seems that it's not.

#include <iostream>

class a {
int v;
public:
a():v(0){}
a& operator++(int) {
v++;
return *this;
}

If the operator++ is written that way, its implementation is not as
intended. The built-in operator++(int) first of all returns an r-value
and second, the value is _before_ the increment. If you make it return
a&, it's not an r-value, and if you 'return *this', by the time the
caller gets the value, the object has already been changed.

See Ron's reply for the "correct" and the intended implementation.
operator int&() {
return v;
}
};

int main() {
a aa;
// I intend to initialize b with 0, then increment a
int b = aa++;
std::cout << b << std::endl;
// didn't happen
}

V
 
A

Andrey Tarasevich

Robert said:
I was then thinking the statement

int b = aa++;

should be equivalent to

b = aa; a++;

Seems that it's not.
...

It never is. In your case it is equivalent to

int b = aa.operator++(0);

It will do whatever you do inside your 'a::eek:perator++'. It will
initialize 'b' with whatever you return from your 'a::eek:perator++'.

You want 'b' to have the old "value" of 'aa'? Then it is your
responsibility to preserve and return that old value from
'a::eek:perator++'. You didn't do that, hence the result.
 
P

Pete Becker

Victor said:
I am not sure what 'inept' is in this case. If your compiler allows
the code to compile, the compiler is non-compliant.

The requirement in the standard isn't that strong. 6.6.3/3: "....
Flowing off the end of a function is equivalent to a return with no
value; this results in undefined behavior in a value-returning
function." Since the behavior is undefined, no diagnostic is required. A
warning is helpful, except that in more complicated functions compilers
often give erroneous warnings.
 
V

Victor Bazarov

Pete said:
The requirement in the standard isn't that strong. 6.6.3/3: "....
Flowing off the end of a function is equivalent to a return with no
value; this results in undefined behavior in a value-returning
function." Since the behavior is undefined, no diagnostic is required. A
warning is helpful, except that in more complicated functions compilers
often give erroneous warnings.

Thank you for the correction, Pete. Not ill-formed, just having undefined
behaviour. Got it.

V
 
R

Robert Swan

The following use of class a is convenient:

a a_inst;
int& b = a;

So far it's working as expected. Have I created a hazard of some sort?
Nah... However, I'd add

operator int() const { return v; }

I assume this is preventing something bad but I can't think of what it
might be.
 
R

Robert Swan

Andrey said:
It never is. In your case it is equivalent to

int b = aa.operator++(0);

It will do whatever you do inside your 'a::eek:perator++'. It will
initialize 'b' with whatever you return from your 'a::eek:perator++'.

You want 'b' to have the old "value" of 'aa'? Then it is your
responsibility to preserve and return that old value from
'a::eek:perator++'. You didn't do that, hence the result.

Cool, thanks for the response. I was thinking that operator ++ was
somehow automatically delayed until after all other operations in the
statement. I now see that it's just another operator, and only "post" if
implemented as such.
 
V

Victor Bazarov

Robert said:
The following use of class a is convenient:

a a_inst;
int& b = a;

You mean,

int& b = a_inst;

don't you? See what happens when classes have such long and convoluted
names?
So far it's working as expected. Have I created a hazard of some sort?

Yes, you created a back door to private data. Now whoever owns 'b' can
change the contents of 'a' without 'a' knowing it. It essentially works
against "data abstraction principle", not that you have to follow it, of
course...
I assume this is preventing something bad but I can't think of what it
might be.

We need to hear from Ron to understand his objection fully. I can only
guess what his objection was about but I won't.

V
 
R

Ron Natalie

The following use of class a is convenient:

a a_inst;
int& b = a;

But may do the wrong thing, I assume you meant:
int &b = a_inst;
a_inst ++;
a_inst ++;

What does b evaluate to?

or did you really want to let people change the private
member of a_inst by doing:
b = 5;
 
R

Robert Swan

Yes, I made an error, should be int& b = a_inst;
But may do the wrong thing, I assume you meant:
int &b = a_inst;
a_inst ++;
a_inst ++;

What does b evaluate to?

or did you really want to let people change the private
member of a_inst by doing:
b = 5;

When I reduced my code to create a suitable newsgroup posting I changed
the meaning. The data refered to was not supposed to be private. So if
the only risk is the access to private data then I'm fine. I just wanted
to use the same syntax to initialize a reference from both an int and
another class.

Thanks for your help.

Robert
 
H

Howard

Ron Natalie said:
You're missing a return here.
If you return
*this
then, the program should behave like you observed.
The v member is incremented and the side effect applied
before the operator++ returns.

If you want it to behave like a real postincrement, you
need to return a copy of the old object.

a operator++(int) {
a temp(*this);
v++;
return a;

I take it you meant:

return temp;

?

-Howard
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,199
Latest member
AnyaFlynn6

Latest Threads

Top