Archived

This topic is now archived and is closed to further replies.

BoRReL

pre or post increment

Recommended Posts

Heya, I read the following in another post and can hardly believe it:
quote:
4. You should ALWAYS use the prefix increment when possible ... because the postfix increment has to make a copy ... and then increment the original. it++ is usually wrong or inefficient .. ++it is the correct way to do it ... as proof ... these lines: i = i + 1; i += 1; ++i; are all identical ... and generate identical code ... this one: i++ is NOT the same ... and is wrong for items without a copy constructor .. or wierd side effects.
Does VStdio''s optimizer not optimize this the proper way?? I don''t think for(i=0;i<10;i++) is slower than for(i=0;i<10;++i), is it? For now I only used the prefix notation with pointers. eg. ++dest = bla. Could somebody clear up my mind?? Gr, BoRReL

Share this post


Link to post
Share on other sites
There are situations in which you particularly want postincrement, but in those cases where increment order is unimportant (like a for loop) use preincrement.

As for whether Visual Studio optimizes the for loop in question, it probably does since the order makes no difference. However, it doesn''t generally optimize your increment choices because it might damage your program logic.



To you it''s a Bently, to me it''s a blue car...
"Diddy"
P.Diddy

Share this post


Link to post
Share on other sites
For integral types (like int) you won''t see any difference concerning the for loops. However if you use complex types (classes) the pre increment may be faster.

Share this post


Link to post
Share on other sites
The only time it would ever matter is if you create your own class and overload the operators - AND it''s not true.

IF the post-incremet ++ calls the copy constructor, so will the pre - and ONLY IF you poorly implement the ++() operators.


  
//No evil copy constructor called

const CMyInt& operator ++()
{
++i;
return *this;
}


Magmai Kai Holmlor
- Not For Rent

Share this post


Link to post
Share on other sites
I don''t know what you intendent to show Magmai Kai Holmlor.
The problem is not the constructor call. But when you are using a postfix operator you have to manipulate your object while you must return its old version.
By the way, your example is a pre increment, if i is a member.

Share this post


Link to post
Share on other sites
To elaborate on what VolkerG said, consider the simple example below:

int i = rand() % 4000;
int j = i++;

What''s the value of j after the assignment? (It''s the original value of i). What''s the value of i? (It''s 1 greater than the original value). How did that happen? The preceding code is evaluated as

j = i;
i = i + 1;

In other words, j = i is equivalent to a copy constructor for more complex data types (operator= is often implemented as a copy constructor, right?) Compare that to the following:

int i = rand() % 4000;
int j = ++i;

In this case, j is assigned the value of i after i has been incremented . There''ll still be a copy, but two values aren''t returned (i++ includes an implicit return of i.)

Operator precedence and associativity can be some freaky stuff at times.

Share this post


Link to post
Share on other sites
Magmai: Thats a prefix-increment operator you defined. Of course there's no need to call the copy constructor in that one, since it should always return a reference to itself. However, in a postfix increment you must return the object as it was before the increment was performed. Therefore you cannot return a reference to *this (assuming the operator actually modifies something). You must create a copy of the object, then perform the increment, and finally return the copy.

e.g.
      
// a prefix increment similar to the one you showed above:

CMyInt& CMyInt::operator ++()
{
++i; // i is a member

return *this;
}

// a corresponding postfix increment:

CMyInt CMyInt::operator ++(int) // the int makes it a postfix

{
CMyInt tmp(*this);
++i;
return tmp;
}

If you can write the postfix version without calling a copy constructor, then please show it.

[EDIT]
Thought about this some more:
Actually the postfix increment operator above uses two copy constructor calls, one to create tmp, and one to copy tmp to the anonymous 'return variable' (perhaps an optimizing compiler can eliminate one of them). Both calls can be avoided by writing a specialized constructor, but then you still get one constructor call (and the code is slightly 'messier'). I don't think it's possible to write a post-increment without calling at least one constructor (assuming you want it to behave similarly to the post-increment for built-in types).
[/EDIT]

Edited by - Dactylos on October 22, 2001 5:09:25 PM

Share this post


Link to post
Share on other sites
What a pos. The overidden operator ++(int) doesn't get called at the same time the native post-inc op does!!! Is this the way it's suppose to work, or is MSVC6 broken? Any standards gurus?

So it only matters if you overload the post-fix operator. For native types the post-fix operator doesn't get called until _after the line it's on finishes executing, even if there's a pile of them on that line. With classes post-fix is called inline on MSVC6, and my stance is that VC6 is thus broken, and/or the C++ is bad if that's the way it's suppose to happen. It means you can't make a class work like a built in type, it's impossible due to the "int q" situation below.

Observe:
    
#include < iostream.h >
#include < conio.h >

class CMyInt
{
public:
CMyInt() : i(0)
{}
CMyInt(const CMyInt& x)
{
cout<<"Evil Copy Constructor"<<endl;
i = x.i;
}

//Broken post-fix

CMyInt& operator ++(int)
{
i++;
return(*this);
}

operator int()
{
cout<<"int operator"<<endl;
return(i);
}

int i;
};


int main(int argc, char* argv[])
{
CMyInt my;
int m=0;

int i=0;
int j=0;
int q=0;


cout<<"i="<<i<<endl<<"j="<<j<<endl;
i = j++;
cout<<"i="<<i<<endl<<"j="<<j<<endl;

cout<<endl<<endl;
cout<<"m="<<m<<endl<<"my.i="<<my.i<<endl;
m = my++;
cout<<"m="<<m<<endl<<"my.i="<<my.i<<endl;

cout<<endl<<endl;
cout<<"i="<<i<<endl<<"q="<<q<<endl;
q = i++, i++, i++;
cout<<"i="<<i<<endl<<"q="<<q<<endl;

getch();
return 0;
}



Magmai Kai Holmlor
- Not For Rent

Edited by - Magmai Kai Holmlor on October 22, 2001 7:45:25 PM

Share this post


Link to post
Share on other sites
quote:
Original post by Magmai Kai Holmlor
So it only matters if you overload the post-fix operator. For native types the post-fix operator doesn''t get called until _after the line it''s on finishes executing, even if there''s a pile of them on that line.


Actually, I''ve wondered about this a number of times. I''m convinced that the postfix increment operator gets called after the statement, which may not correlate to the line. ie,

int i = 1;
int a = i++ + ++i;

has some interesting behavior. a probably ends up as 3, and so does i. (i++) is evaluated after the statement i + d, where d = ++i = 2. So a = 1 + 2, then i = 2 + 1.

Fascinating, isn''t it?

Share this post


Link to post
Share on other sites
*Where* the increment/decrement occurs is very compiler dependant. I'd say MSVC is broken. For me the logical is to assume that it is treated as an inline function-call (you seem to agree with me). A friend of mine did a little test of this about a year ago. The result was that Sun's Java VM (ok, so it's not C++ ), and GCC (don't remember the version-number) implemented it 'correctly', while the 5 or 6 other compilers he tested (MSVC++ included) implemented it in a non-intuitive way.

[EDIT: Just to clarify, I'm talking about built-in types here]

Edited by - Dactylos on October 22, 2001 8:13:03 PM

Share this post


Link to post
Share on other sites
I''d prefer post-statement and never inline :p I think MSVC is broken because it evaluates class post-inc inline.

And I''d prefer it to be the same for built-in types and classes rather than different. And the same on compilers, even if it didn''t work the way I wanted it too.

Maybe ''post-precendant'' would be the most intuitive.

int x=0;
int y=0;
int i=0;
x = i++; //x ought to be 0
y = (i++); //y ought to be 2 (in MSVC my money''s on 1)

Share this post


Link to post
Share on other sites