i++ , or ++i, which is faster?

G

guru.slt

"the c++ standard library, tutorial and reference" book, it says:

++i is faster than i++. the latter involves a temporary object because
it must return the old value/object of i. for this reason, it's
generally better to use ++i.

but, I think, even ++i still has to return a temporary object that is
with new value inside. So, both i++ and ++i have to return a temporary
object. Then, what's the speed difference between i++ and ++i.
 
H

Howard

"the c++ standard library, tutorial and reference" book, it says:

++i is faster than i++. the latter involves a temporary object because
it must return the old value/object of i. for this reason, it's
generally better to use ++i.

but, I think, even ++i still has to return a temporary object that is
with new value inside. So, both i++ and ++i have to return a temporary
object. Then, what's the speed difference between i++ and ++i.

The prefix version returns by reference, so no temporary copy is needed.

-Howard
 
D

David Lee Conley

"the c++ standard library, tutorial and reference" book, it says:

++i is faster than i++. the latter involves a temporary object because
it must return the old value/object of i. for this reason, it's
generally better to use ++i.

but, I think, even ++i still has to return a temporary object that is
with new value inside. So, both i++ and ++i have to return a temporary
object. Then, what's the speed difference between i++ and ++i.

I'm still learning C/C++, but the chapter I just finished dealt with
overloading operators, including postfix and prefix increment/decrement.
According to my understanding and the assignment I did, the prefix
increment/decrement, ++i in your example, increases the value of the object,
and then returns it. The postfix increment/decrement, i++ in your example,
copies the current value of the object, increases the current value of the
object, and returns the value of the copy. Thus, prefix only has two steps,
where postfix has three.

Is my interpretation correct?

Dave
 
K

Kristo

"the c++ standard library, tutorial and reference" book, it says:

++i is faster than i++. the latter involves a temporary object because
it must return the old value/object of i. for this reason, it's
generally better to use ++i.

but, I think, even ++i still has to return a temporary object that is
with new value inside. So, both i++ and ++i have to return a temporary
object. Then, what's the speed difference between i++ and ++i.

No, I think ++i returns a reference to i. ++i returns a new object
containing the old value of i. For primitive types, the speed
difference negligible. But, if you wrote a class that allocated 10
megabytes of memory for each instance, the difference would be huge.

Kristo
 
S

Steven T. Hatton

"the c++ standard library, tutorial and reference" book, it says:

++i is faster than i++. the latter involves a temporary object because
it must return the old value/object of i. for this reason, it's
generally better to use ++i.

but, I think, even ++i still has to return a temporary object that is
with new value inside. So, both i++ and ++i have to return a temporary
object. Then, what's the speed difference between i++ and ++i.

This is an abomination, uh, I mean to say class, I created that demonstrates
the difference rather well. Notice that in the postfix case I have to
check to see if there is a temporary object, create it if it doesn't exist,
and assign to it if it does exits. In the prefix form, there is no need to
deal with the temporary object, so there are fewer instructions executed
per call.

I didn't see an obvious way of moving the creation of the temporary object
into constructor since that would lead to unbounded recursion. I could
probably be done by passing some kind of flag to a special constructor.
That might marginally improve performance, but will not make the postfix
form as efficient as the prefix form. Also be aware that I have not tested
the version presented here in so much as it derives from the
util::Referenced baseclass. Additionally, I am less than fully comfortable
with the choice of wrapping the index at the bounds. It does not follow
STL semantics for iterators, and adds a bit of overhead with the '%'
operations.

/***************************************************************************
* Copyright (C) 2005 by Steven T. Hatton *
* (e-mail address removed) *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *

***************************************************************************/
#ifndef MATH_BOUNDEDINDEX_H
#define MATH_BOUNDEDINDEX_H

#include <util/Referenced.h>

namespace math {

/*!\brief The BoundedIndex class provides an \c unsigned \c int in the
range \e [0,supremum)

BoundedIndex represents an \c unsigned \c int ragning from \c 0 \e
inclusive
to \c supremum \e exclusive. It provides both C-style increment and
decrement operators (++,--)
as well as Java-style iterator functions (next(), hasNext()) with
bidirectional functionality.
When the value is incremented beyond either bound, it wraps to the
opposing end of the range.
*/
class BoundedIndex: public util::Referenced {
public:

/*!
Constructor creates 0 range index. Intended to support collection
construction;
*/
BoundedIndex()
:_index(0)
,_sup(0)
,_tmp_ptr(0)
{}

/*!
Constructor
The index value is initialized to 0.
\param sup_ value of \c supremum \e exclusive.
*/
explicit BoundedIndex(unsigned sup_)
:_index(0)
,_sup(sup_)
,_tmp_ptr(0)
{}

/*!
Copy Constructor copies both \c index and \c supremum.
*/
BoundedIndex(const BoundedIndex& b)
:_index(b._index)
,_sup(b._sup)
,_tmp_ptr(0)
{}

/*!
Assignment Operator copies both \c index and \c supremum.
*/
BoundedIndex& operator=(const BoundedIndex& b) {
if(b == *this) return *this;
_sup = b._sup;
_index = b._index;
_tmp_ptr = 0;
}

/*!
Assignment operator clamps \c index to \e [0,supremum)
\param index_ The new index value before clamping.
*/
BoundedIndex& operator=(const unsigned& index_) {
_index = index_ % _sup;
return *this;
}

/*!
Conversion operator converts to \c unsigned \c int.
*/
operator unsigned () const { return _index; }

/*!
Prefix increment operator
*/
BoundedIndex& operator++() {
_index = (_index + 1) % _sup;
return *this;
}

/*!
Postfix increment operator
*/
const BoundedIndex& operator++(int) {
if(!_tmp_ptr) _tmp_ptr = new BoundedIndex(*this); else
_tmp_ptr->_index = _index;
_index = (_index + 1) % _sup;
return *_tmp_ptr;
}

/*!
Prefix decrement operator
*/
const BoundedIndex& operator--() {
_index = _index < 1 ? _sup - 1: _index - 1;
return *this;
}

/*!
Postfix decrement operator
\return reference to a temporary copy of this.
*/
BoundedIndex& operator--(int) {
if(!_tmp_ptr) _tmp_ptr = new BoundedIndex(*this); else
_tmp_ptr->_index = _index;
_index = (_index + 1) % _sup;
return *_tmp_ptr;
}

/*!
Compund assignment addition operator.
\return reference to this.
*/
BoundedIndex& operator+=(const unsigned& di_) {
_index = (_index + di_)%_sup;
return *this;
}

/*!
Compund assignment subtraction operator.
\return reference to this.
*/
BoundedIndex& operator-=(const unsigned& di_) {
_index = _index >= di_? (_index - di_): _sup - (di_ - _index)%_sup;
return *this;
}

/*!
Accessor
\return value of \c supremum
*/
unsigned sup() const { return _sup; }

/*!
Mutator
\param sup_ set the value of \c supremum.
*/
void sup(unsigned sup_ ) { _sup = sup_; }

/*!
Accessor
\return value of \c index
*/
unsigned index() const { return _index; }

/*!
Mutator
\param index_ set the value of \c index.
*/
void index(unsigned index_ ) { _index = index_; }

/*!
Tests whether the index can be increased;
*/
bool hasNext() const { return _index < _sup - 1; }

/*!
Tests whether the index can be decreased;
*/
bool hasPrevious() const { return _index > 0; }

/*!
Wrapper for operator++();
*/
BoundedIndex& next() { return operator++(); }

/*!
Wrapper for operator--();
*/
BoundedIndex& previous() { return operator--(); }

protected:
/*!
Destructor.
*/
~BoundedIndex() { delete _tmp_ptr; }

private:
unsigned _index;
unsigned _sup;
BoundedIndex* _tmp_ptr;
};

/*!
BoundedIndex binary addition operator;
*/
BoundedIndex operator+(const BoundedIndex& arg1, const BoundedIndex& arg2)
{
BoundedIndex ret(arg1);
return ret += arg2;
}

/*!
BoundedIndex binary subtraction operator;
*/
BoundedIndex operator-(const BoundedIndex& arg1, const BoundedIndex& arg2)
{
BoundedIndex ret(arg1);
return ret -= arg2;
}
}


#endif
 
G

guru.slt

I see, thanks!

i++ is:

template<class T>
T foo (T& i) {
T temp(i);
i = i+1;
return temp;
}

++i is:
template<class T>
T& foo(T& i) {
i = i+1;
return i; }
 
V

Victor Bazarov

Kristo said:
No, I think ++i returns a reference to i.

You meant 'i++'...
returns a new object
containing the old value of i. For primitive types, the speed
difference negligible. But, if you wrote a class that allocated 10
megabytes of memory for each instance, the difference would be huge.

I just wonder why is everybody in a rush to type up an answer to a FAQ
that is actually in _the_FAQ_ (and make a few typos on the way)?...

I am really puzzled by it. Honestly.

V
 
G

guru.slt

/*!
Prefix increment operator
*/
BoundedIndex& operator++() {
_index = (_index + 1) % _sup;
return *this;
}

/*!
Postfix increment operator
*/
const BoundedIndex& operator++(int) {
if(!_tmp_ptr) _tmp_ptr = new BoundedIndex(*this); else
_tmp_ptr->_index = _index;
_index = (_index + 1) % _sup;
return *_tmp_ptr;
}

Thanks!
 
H

Howard

Please don't top-post. I've re-arranged things properly below:
i++ is:

template<class T>
T foo (T& i) {
T temp(i);
i = i+1;
return temp;
}

++i is:
template<class T>
T& foo(T& i) {
i = i+1;
return i; }

Where did you get those? That's not how they're implemented at all. A
proper prefix increment (or decrement) operator returns *this, a reference
to the current object. What you've shown is returning a reference to a
local object, which is not valid because the object goes out of scope at the
end of the function. Also, the function signatures are incorrect.

I suggest you get a better book.

-Howard
 
V

Victor Bazarov

Howard said:
Where did you get those? That's not how they're implemented at all. A
proper prefix increment (or decrement) operator returns *this, a reference
to the current object. What you've shown is returning a reference to a
local object, which is not valid because the object goes out of scope at the
end of the function. Also, the function signatures are incorrect.

You seem to presume that the functions are members. There is no such
requirement. The 'foo' things here are stand-alone functions, just
showing the semantics of post- and pre-increment.
I suggest you get a better book.

What if you do, as well?

V
 
P

Pete Becker

Howard said:
Where did you get those? That's not how they're implemented at all. A
proper prefix increment (or decrement) operator returns *this, a reference
to the current object.

Only if it's a member function. That's not required, though. These are
standalone functions, so they can't return *this.
What you've shown is returning a reference to a
local object, which is not valid because the object goes out of scope at the
end of the function.

The first function returns a local object by value. No problem. The
second one returns a reference to the argument that was passed to it by
reference. No problem.
Also, the function signatures are incorrect.

Yes, the signatures aren't appopriate for increments. But, then, neither
are the names, so I suspect the intent was just what the message says:
to illustrate how to implement them, which this code does.
 
S

Steven T. Hatton

Victor said:
You meant 'i++'...


I just wonder why is everybody in a rush to type up an answer to a FAQ
that is actually in _the_FAQ_ (and make a few typos on the way)?...

I am really puzzled by it. Honestly.

V

The response I provided was not provided in the FAQ, and the example in the
FAQ would not have worked for the class I presented. The solution provided
in the FAQ uses an automatic variable rather than a class member for the
return value of the postfix operator. The FAQ example does not return a
reference so it also has to invoke a copy constructor. I don't fully
understand the consequences of returning a non-const reference, but that
seems wrong to me. The user could conceivably hold onto that reference and
subsequently modify the variable through it. My version doesn't permit
that.
 
S

Swampmonster

"the c++ standard library, tutorial and reference" book, it says:

++i is faster than i++. the latter involves a temporary object because
it must return the old value/object of i. for this reason, it's
generally better to use ++i.

but, I think, even ++i still has to return a temporary object that is
with new value inside. So, both i++ and ++i have to return a temporary
object. Then, what's the speed difference between i++ and ++i.

If "i" is an instance of any builtin type (int, char, something*, ...)
then just forget it and use whatever you want - the speed will be the
same.

If "i" is an instance of a template, and you're compiler is smart and
you do enable optimizations for your release-build, then the speed
difference will be little to none - depending on the
template-class of course - but for iterators both should be fine.

Finally, if "i" is a non-template, non-inline class (more specific:
the implementation of the copy-constructor or "++" operators are not
inline) - then the "++i" will probably be faster. But for a "full blown
class" overloading operator "++" seems somehow ... strange to me.

All in all I think the whole "++i is better then i++" thing is
overrated.
 
A

Alf P. Steinbach

* (e-mail address removed):
"the c++ standard library, tutorial and reference" book, it says:

++i is faster than i++. the latter involves a temporary object because
it must return the old value/object of i. for this reason, it's
generally better to use ++i.

The above is nonsense.

++i _can_ be faster than i++, and ++i _can_ be supported where i++ is not.

However, the main reason you should (as a general rule) stay away from
i++ is that it's only meaningful for producing a side-effect, which is very
likely to give you Undefined Behavior.
 
H

Howard

Victor Bazarov said:
You seem to presume that the functions are members. There is no such
requirement. The 'foo' things here are stand-alone functions, just
showing the semantics of post- and pre-increment.

Ok, yes, I was presuming members. (That's all I saw under the section that
discussed increment and decrement operators. An earlier section showed some
non-member versions.)

(And his naming them foo instead of "operator ++" saved him a few
keystrokes, but makes things confusing when we're discussing operator ++.)
What if you do, as well?

I'm using Stroustrup's TCPL, which is a pretty good book. It shows the
following signatures for member ++ operators:

X& operator++(); // prefix
X operator ++(int); // postfix

The non-member versions would be:

X& operator ++(); // prefix
X operator++(X&,int); // postfix

The presence of the extra dummy (int) parameter allows the compiler to
determine whether it's prefix or postfix. How would the compiler know which
of the above (foo) functions to call?

-Howard
 
C

Clark S. Cox III

* (e-mail address removed):

The above is nonsense.

++i _can_ be faster than i++, and ++i _can_ be supported where i++ is not.

However, the main reason you should (as a general rule) stay away from
i++ is that it's only meaningful for producing a side-effect, which is very
likely to give you Undefined Behavior.

Both (++i) and (i++) have the exact same side effect, which is to
increment i. i can't see how one is any more likely to cause UB than
the other.
 
S

Steven T. Hatton

Clark said:
Both (++i) and (i++) have the exact same side effect, which is to
increment i. i can't see how one is any more likely to cause UB than
the other.

How can you say that as a general rule? What does it even mean to increment
i for an arbitrary class?
 
A

Alf P. Steinbach

* Clark S. Cox III:
Both (++i) and (i++) have the exact same side effect, which is to
increment i.

Nope, they don't mean the same thing.

i can't see how one is any more likely to cause UB than
the other.

It isn't, but side-effect based code is.

Cheers,

- Alf
 
C

Clark S. Cox III

* Clark S. Cox III:

Nope, they don't mean the same thing.

I didn't say they meant the same thing (they don't, they have different
values), but they do have the same side effect.
It isn't, but side-effect based code is.

If you expect either operator to increment i, then you are relying on
side effects. Without the side-effects, neither operator would be of
any use at all.
 
C

Clark S. Cox III

How can you say that as a general rule? What does it even mean to increment
i for an arbitrary class?

I can't say for an arbitrary class. But, my point was that "[i++]'s
only meaningful for producing a side-effect" is nonsense. Without side
effects, both operators would be useless; not just the postfix version.
 

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
474,298
Messages
2,571,542
Members
48,283
Latest member
RitaVui655

Latest Threads

Top