lvalue required as increment operand -- why does the Standard requiresthis for fundamental types on

P

Pavel

In the code below, the increment on a function call expression of type "int"
does not compile but the one on a function call expression of class Int compiles
fine. My understanding is (please correct me if I am wrong) that it directly
follows from 3.10 and 5.3-2 of the current Standard and (also please correct me
if I am wrong here) that this is no different in the upcoming C++0x Standard.

What is the rationale for this lvalue requirement if there is one?

My suspicion is that it may be related to an optimization opportunity for a C++
compiler but I could not come up with a satisfactory guess on what it could be.
To rephrase my question, am I writing a potentially sub-optimal code if I always
use a thin class wrapper around a fundamental integral or pointer type as
opposed to using it outright? (I use a wrapper, in particular, to be able to
call ++ on the function's return value; this is an advantage in my case -- but
is there a downside other than having to write the wrapper?)

TIA,
-Pavel


-----------------
int f1() { return 5; }

class Int {
public:
explicit Int(int i) : i_(i) {}
Int & operator++() { ++i_; return *this; }
private:
int i_;
};

Int f2() { return Int(5); }

int main(int, char *[]) {
//int i1 = ++f1(); (void)i1; // this does not compile
Int i2 = ++f2(); (void)i2; // this compiles fine
return 0;
}
 
S

SG

What is the rationale for this lvalue requirement if there is one?

-----------------
int f1() { return 5; }

class Int {
public:
   explicit Int(int i) : i_(i) {}
   Int & operator++() { ++i_; return *this; }
private:
   int i_;
};

Int f2() { return Int(5); }

int main(int, char *[]) {
//int i1 = ++f1(); (void)i1; // this does not compile
   Int i2 = ++f2(); (void)i2; // this compiles fine
   return 0;

Why do you even want the first one to compile? f1 simply returns a
value. If you want f1()+1 then write f1()+1. There is abolutely no
reason to support prefix ++ on things that don't refer to any object.
Check the C++ standard w.r.t. the C++ object model and lvalue/rvalue
expressions. You'll see that an rvalue of type int does NOT refer to
an object whereas an rvalue of type Int _does_ refer to an object
because Int is a class type. Now, why does C++ allow you to invoke a
nonconst member function on a temporary object? Answer: Why not? It
may be useful. Whether you overloaded an operator or wrote a function
with some other name does not matter. Your overloaded operator++ could
have other side effects which would make ++f2() do something useful.

Cheers!
SG
 
P

Pavel

SG said:
What is the rationale for this lvalue requirement if there is one?

-----------------
int f1() { return 5; }

class Int {
public:
explicit Int(int i) : i_(i) {}
Int& operator++() { ++i_; return *this; }
private:
int i_;
};

Int f2() { return Int(5); }

int main(int, char *[]) {
//int i1 = ++f1(); (void)i1; // this does not compile
Int i2 = ++f2(); (void)i2; // this compiles fine
return 0;

Why do you even want the first one to compile? f1 simply returns a
value. If you want f1()+1 then write f1()+1.
Because in a generic algorithms, f()+1 and ++f() for some (class) types may not
be equivalent (in particular, f() + 1 is often slower than ++f() for class
types). I want my algo to compile on both fundamental and class types and do not
want to sacrifice performance on class types if I do not have to. An example of
a (class) type for which operator+(some_distance_type) and operator++() may have
different performance is a list iterator.

There is abolutely no
reason to support prefix ++ on things that don't refer to any object.
Thanks, I knew that already. This was not not my question. The question was
about the specific rationale for this decision of the Standard's authors.
Check the C++ standard w.r.t. the C++ object model and lvalue/rvalue
expressions. You'll see that an rvalue of type int does NOT refer to
an object whereas an rvalue of type Int _does_ refer to an object
because Int is a class type.
Thanks, but that was not my question. I know (or I believe I know) how the
observed behavior is compliant with the Standard. I am asking for a rationale.

Now, why does C++ allow you to invoke a
nonconst member function on a temporary object?
Thanks, it was not my question again.

Answer: Why not? It
may be useful. Whether you overloaded an operator or wrote a function
with some other name does not matter. Your overloaded operator++ could
have other side effects which would make ++f2() do something useful.

Cheers!
SG

Thanks,
-Pavel
 
S

SG

Pavel said:
SG said:
On 2 Jul., 19:30, Pavel wrote:
What is the rationale for this lvalue requirement if there is one?
There is abolutely no reason [for C++] to support prefix ++ on things
that don't refer to any object.
Thanks, I knew that already. This was not not my question. The
question was about the specific rationale for this decision of the
Standard's authors.

You are missing the point.

I have the same feeling. Maybe I left out some detail that is obvious
to most but not Pavel.
Supporting ++ on non-objects is logically
infeasible, [...]

....because ++ means "increment that thing and return the new value"
and you don't want 5 to be 6. ;-) But maybe I simply didn't get the
question.

As for genericity: You may implement your own iterator's prefix ++ via
a member function. But incrementing rvalue iterators is still not part
of the iterator concept! Otherwise, raw pointers wouldn't be
iterators. If you want to code generically you better limit yourself
to the concepts' interfaces.

The standard library of the upcoming C++ ISO standard will provide two
helper functions: prev and next after including <iterator>. Then you
can write things like

auto second = next(container.begin());

if you want to. I think Boost provides something similar already and
it's easy to do it yourself:

template<class Iter>
inline Iter next(Iter it) { std::advance(it,1); return it; }

Cheers!
SG
 
P

Pavel

Paavo said:
SG said:
On 2 Jul., 19:30, Pavel wrote:

What is the rationale for this lvalue requirement if there is one?
[...]

There is abolutely no
reason to support prefix ++ on things that don't refer to any object.
Thanks, I knew that already. This was not not my question. The
question was about the specific rationale for this decision of the
Standard's authors.

You are missing the point. Supporting ++ on non-objects is logically
infeasible, it's like writing "++5;" in your program. As we all know from
endless threads with Paul, an object is a region of memory, having a
certain memory address. The ++ operator would presumable update this
region of memory somehow, and later the changed content could be observed
by using the same address. If there is no memory region, what should be
updated? Or if you say a content of CPU register could be updated, how
could you refer to it afterwards to have any usage of the changes?
I think SG knew what I wanted to do.

say, for --:

template <class C> void foo(C &c) {
assert(!c.empty());
typename C::iterator lastElemIter = --c.end();
.... // use lastElemIter here
}

would give me an iterator to the last element. It works if the iterator's
implementation happen to be a class and does not if it is happen to be a
pointer. I hope this answers yours and SC's questions on how I am to use these.

If you know how to fix this code to compile for both class-type and
fundamental-type iterators, without any temporary variables, if possible, I
would appreciate your suggestion.

This
would require some other language, having different rules. I think in
some languages one can even change the value of numeric literals ;-)

Now if you changed f1 to read e.g.

int& f1() { return 5; }
I hope you see now it is not relevant to my question. I do not see any
conceptual difference between returning structure Int consisting of a single
integer or a bare integer, by value. Both can be and in fact are placed by
optimizing compilers to registers. C++ Standard does say one is an rvalue
pointing to an object and does not say it about the other; this is clearly a
free choice of the Standard authors, not a logical consequence to anything as
far as I can see and I would like to know the reason for this choice.
then the functions would become more similar and we could discuss further
what is allowed and why.

Cheers
Paavo

TIA
-Pavel
 
P

Pavel

SG said:
Pavel said:
SG wrote:
On 2 Jul., 19:30, Pavel wrote:
What is the rationale for this lvalue requirement if there is one?
There is abolutely no reason [for C++] to support prefix ++ on things
that don't refer to any object.
Thanks, I knew that already. This was not not my question. The
question was about the specific rationale for this decision of the
Standard's authors.

You are missing the point.

I have the same feeling. Maybe I left out some detail that is obvious
to most but not Pavel.
Supporting ++ on non-objects is logically
infeasible, [...]

...because ++ means "increment that thing and return the new value"
and you don't want 5 to be 6. ;-)
I do not think my code implies any such semantics. My f1() returns int by value.
So it says "return a copy of this thing and then increment it".

But maybe I simply didn't get the
question.

As for genericity: You may implement your own iterator's prefix ++ via
a member function. But incrementing rvalue iterators is still not part
of the iterator concept! Otherwise, raw pointers wouldn't be
iterators. If you want to code generically you better limit yourself
to the concepts' interfaces.

The standard library of the upcoming C++ ISO standard will provide two
helper functions: prev and next after including<iterator>. Then you
can write things like

auto second = next(container.begin());

if you want to. I think Boost provides something similar already and
it's easy to do it yourself:

template<class Iter>
inline Iter next(Iter it) { std::advance(it,1); return it; }
This is essentially what I need semantically. Performance-wise, however, I want
to avoid std::advance, because it may be and often is less efficient for many
iterators (e.g. list or map iterators -- which are usually class object and for
which ++ would work).

Cheers!
SG

-Pavel
 
K

Kai-Uwe Bux

Pavel said:
SG wrote: ....
This is essentially what I need semantically. Performance-wise, however, I
want to avoid std::advance, because it may be and often is less efficient
for many iterators (e.g. list or map iterators -- which are usually class
object and for which ++ would work).

Then, what about:

template < typename Iter >
Iter next ( Iter iter ) {
++ iter;
return ( iter );
}


Best,

Kai-Uwe Bux
 
L

Leo \Equinox\ Gaspard

Le 03/07/2011 21:12, Pavel a écrit :
SG said:
Pavel wrote:
SG wrote:
On 2 Jul., 19:30, Pavel wrote:
What is the rationale for this lvalue requirement if there is one?
There is abolutely no reason [for C++] to support prefix ++ on things
that don't refer to any object.
Thanks, I knew that already. This was not not my question. The
question was about the specific rationale for this decision of the
Standard's authors.

You are missing the point.

I have the same feeling. Maybe I left out some detail that is obvious
to most but not Pavel.
Supporting ++ on non-objects is logically
infeasible, [...]

...because ++ means "increment that thing and return the new value"
and you don't want 5 to be 6. ;-)
I do not think my code implies any such semantics. My f1() returns int
by value. So it says "return a copy of this thing and then increment it".

But maybe I simply didn't get the
question.

As for genericity: You may implement your own iterator's prefix ++ via
a member function. But incrementing rvalue iterators is still not part
of the iterator concept! Otherwise, raw pointers wouldn't be
iterators. If you want to code generically you better limit yourself
to the concepts' interfaces.

The standard library of the upcoming C++ ISO standard will provide two
helper functions: prev and next after including<iterator>. Then you
can write things like

auto second = next(container.begin());

if you want to. I think Boost provides something similar already and
it's easy to do it yourself:

template<class Iter>
inline Iter next(Iter it) { std::advance(it,1); return it; }
This is essentially what I need semantically. Performance-wise, however,
I want to avoid std::advance, because it may be and often is less
efficient for many iterators (e.g. list or map iterators -- which are
usually class object and for which ++ would work).

AFAIK it is not the case.
advance(N, it) will internally call ++ N times if the operator isn't a
random access one. So advance(1, it) should be as efficient as ++it,
except maybe a function call, if it ever was not inlined.

Cheers,
Leo
 
L

Leo \Equinox\ Gaspard

Le 03/07/2011 20:51, Pavel a écrit :
Paavo said:
SG wrote:
On 2 Jul., 19:30, Pavel wrote:

What is the rationale for this lvalue requirement if there is one?

-----------------
int f1() { return 5; } [...]
int main(int, char *[]) {
//int i1 = ++f1(); (void)i1; // this does not compile [...]

There is abolutely no
reason to support prefix ++ on things that don't refer to any object.
Thanks, I knew that already. This was not not my question. The
question was about the specific rationale for this decision of the
Standard's authors.

You are missing the point. Supporting ++ on non-objects is logically
infeasible, it's like writing "++5;" in your program. As we all know from
endless threads with Paul, an object is a region of memory, having a
certain memory address. The ++ operator would presumable update this
region of memory somehow, and later the changed content could be observed
by using the same address. If there is no memory region, what should be
updated? Or if you say a content of CPU register could be updated, how
could you refer to it afterwards to have any usage of the changes?
I think SG knew what I wanted to do.

say, for --:

template <class C> void foo(C &c) {
assert(!c.empty());
typename C::iterator lastElemIter = --c.end();
... // use lastElemIter here
}

would give me an iterator to the last element. It works if the
iterator's implementation happen to be a class and does not if it is
happen to be a pointer. I hope this answers yours and SC's questions on
how I am to use these.

If you know how to fix this code to compile for both class-type and
fundamental-type iterators, without any temporary variables, if
possible, I would appreciate your suggestion.

typename C::iterator lastElemIter = c.end(); --lastElemIter;

No temporary variables are created, as the compiler is likely to
optimize the return type of the function. Indeed, I believe that for
class types the second one is even more efficient, as it could use only
move-constructor, whereas yours implies a move and a copy constructor.

However, I believe the compiler would optimize all of it so the two
expressions would act the same way - except that "mine" would work with
any iterator type.

And std::prev(it) (or boost::prior(it)) would also do as you want.

Cheers,
Leo
 
P

Pavel

Kai-Uwe Bux said:
Then, what about:

template< typename Iter>
Iter next ( Iter iter ) {
++ iter;
return ( iter );
}
Thanks, that would work. In my actual code, I put up with the temporary
variable. because adding a new function for this purpose is not enough bang for
the buck (the bang being not having to add the temporary and the buck being the
readers of my code having to learn a new function). When it is the part of the
Standard it probably will be better to use that new next().

I just thought -- why this restriction is in the Standard? Mainly I am concerned
that my own iterators and such implemented as classes could be sub-optimal to
fundamental-type implementations? That's why I was asking for the reason..

-Pavel
 
P

Pavel

Leo said:
Le 03/07/2011 21:12, Pavel a écrit :
SG said:
Pavel wrote:
SG wrote:
On 2 Jul., 19:30, Pavel wrote:
What is the rationale for this lvalue requirement if there is one?
There is abolutely no reason [for C++] to support prefix ++ on things
that don't refer to any object.
Thanks, I knew that already. This was not not my question. The
question was about the specific rationale for this decision of the
Standard's authors.

You are missing the point.

I have the same feeling. Maybe I left out some detail that is obvious
to most but not Pavel.

Supporting ++ on non-objects is logically
infeasible, [...]

...because ++ means "increment that thing and return the new value"
and you don't want 5 to be 6. ;-)
I do not think my code implies any such semantics. My f1() returns int
by value. So it says "return a copy of this thing and then increment it".

But maybe I simply didn't get the
question.

As for genericity: You may implement your own iterator's prefix ++ via
a member function. But incrementing rvalue iterators is still not part
of the iterator concept! Otherwise, raw pointers wouldn't be
iterators. If you want to code generically you better limit yourself
to the concepts' interfaces.

The standard library of the upcoming C++ ISO standard will provide two
helper functions: prev and next after including<iterator>. Then you
can write things like

auto second = next(container.begin());

if you want to. I think Boost provides something similar already and
it's easy to do it yourself:

template<class Iter>
inline Iter next(Iter it) { std::advance(it,1); return it; }
This is essentially what I need semantically. Performance-wise, however,
I want to avoid std::advance, because it may be and often is less
efficient for many iterators (e.g. list or map iterators -- which are
usually class object and for which ++ would work).

AFAIK it is not the case.
advance(N, it) will internally call ++ N times if the operator isn't a
random access one. So advance(1, it) should be as efficient as ++it,
except maybe a function call, if it ever was not inlined.
Thanks Leo,

To do something N times, compiler have to do at least one branch which is not
necessary for doing that same thing exactly 1 time. Unless advance()
implementation is at the same translation unit (which may not be the case for
map iterators etc) compiler cannot optimize out that branch.

My question is more about the reason for the distinction. Many subtle "gotchas"
or seeming weirdnesses in the Standard were introduced to keep particular
optimization options open (whether all of them were in fact useful is another
question). I am just curious if I am missing anything here. One of the declared
and more or less consistently pursued goals of C++ was to ensure uniform syntax
for operations on the objects of fundamental (language's) and class (user's)
types. The language walked great lengths to fulfill this promise (including the
whole operator overloading business that I personally disapprove of). Thus I
suspect there was/is a reason for this particular discrepancy in type handling
and I would like to know what it is (and why it is kept as is in C++0x if it was
not good enough a reason).

-Pavel
 
P

Pavel

Leo said:
Le 03/07/2011 20:51, Pavel a écrit :
Paavo said:
SG wrote:
On 2 Jul., 19:30, Pavel wrote:

What is the rationale for this lvalue requirement if there is one?

-----------------
int f1() { return 5; }
[...]
int main(int, char *[]) {
//int i1 = ++f1(); (void)i1; // this does not compile
[...]

There is abolutely no
reason to support prefix ++ on things that don't refer to any object.
Thanks, I knew that already. This was not not my question. The
question was about the specific rationale for this decision of the
Standard's authors.

You are missing the point. Supporting ++ on non-objects is logically
infeasible, it's like writing "++5;" in your program. As we all know
from
endless threads with Paul, an object is a region of memory, having a
certain memory address. The ++ operator would presumable update this
region of memory somehow, and later the changed content could be
observed
by using the same address. If there is no memory region, what should be
updated? Or if you say a content of CPU register could be updated, how
could you refer to it afterwards to have any usage of the changes?
I think SG knew what I wanted to do.

say, for --:

template <class C> void foo(C &c) {
assert(!c.empty());
typename C::iterator lastElemIter = --c.end();
... // use lastElemIter here
}

would give me an iterator to the last element. It works if the
iterator's implementation happen to be a class and does not if it is
happen to be a pointer. I hope this answers yours and SC's questions on
how I am to use these.

If you know how to fix this code to compile for both class-type and
fundamental-type iterators, without any temporary variables, if
possible, I would appreciate your suggestion.

typename C::iterator lastElemIter = c.end(); --lastElemIter;

No temporary variables are created, as the compiler is likely to
optimize the return type of the function. Indeed, I believe that for
class types the second one is even more efficient, as it could use only
move-constructor, whereas yours implies a move and a copy constructor.

However, I believe the compiler would optimize all of it so the two
expressions would act the same way - except that "mine" would work with
any iterator type.
Thanks, yes, it will. It is just a little nuisance; I just wanted to know the
reason for the difference.

When I was talking temporary variable I had the actual case where the iterator
to the last element was to be returned from a function, e.g.

....
if (<cond>)
return --c.end();
....

as opposed to

if (<cond>) {
typename C::iterator i = c.end();
return --i; // i is a temporary here
}

sorry for the confusion.
And std::prev(it) (or boost::prior(it)) would also do as you want.
boost::prior() would help (because it is an overload). Unfortunately, I can't
use boost in many projects.

std::prev(), as it is now planned will, unfortunately, have a second parameter
of difference_type type so it will have same performance issues as std::advance().

Again, my question was not about the particular use case (I just gave it to
illustrate why the uniform spec could be useful), but about the reason for the
discrimination between the fundamental and class types in this regard.

-Pavel
 
S

SG

[...]

template <class C> void foo(C &c) {
    assert(!c.empty());
    typename C::iterator lastElemIter = --c.end();
... // use lastElemIter here
}

would give me an iterator to the last element. It works if the iterator's
implementation happen to be a class

Not necessarily. operator-- could be implemented as a free function
taking an lvalue reference parameter. And it would be ok to do so
because the ITERATOR CONCEPT only requires ++ and -- (for
bidirectional iterators) to work on LVALUES. We have interfaces for a
reason. Don't rely on specific implementations!

This is essentially what I need semantically. Performance-wise, however, I want
to avoid std::advance, because it may be and often is less efficient for many
iterators (e.g. list or map iterators -- which are usually class object and for
which ++ would work).

These are bidirectional iterators. For such iterators std::advance
maps to something like this via tag dispatching:

template<class Iter>
inline void advance_(
Iter & it,
typename iterator_traits<Iter>::difference_type d,
bidirectional_iterator_tag)
{
if (d<0) {
while (d++ < 0) --it;
} else {
while (d-- > 0) ++it;
}
}

Compared to ++it, advance(it,1) only requires two additional tests --
that is, unless the compiler inlines this function and applies some
dead branch elimination because the value d is known to be 1 at
compile time during inlining.

Of course, why write advance(it,1) if you can write ++it directly? I
don't know. That's just how the upcoming standard describes the
behaviour of std::next. I guess implementers will simply write this

template<class Iter>
inline Iter next(Iter x) { ++x; return x; }

considering the "as-if rule".

And just for the fun of it, let's ACTUALLY test how G++ optimizes
advance with a constant second parameter of value 1 for list
iterators:

#include <iterator>
#include <list>

typedef std::list<int>::iterator iter;

iter next(iter it) {
std::advance(it,1);
return it;
}

--[ g++ -O3 advance.cpp && objdump -Cd advance.o ]-->

00000000 <next(std::_List_iterator<int>)>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 8b 45 08 mov 0x8(%ebp),%eax
6: 8b 00 mov (%eax),%eax
8: c9 leave
9: c3 ret
a: 90 nop
b: 90 nop

I see no loop, no tests of any kind. In fact, when I replace
advance(it,1) with ++it, I see EXACTLY the same assembly code.
Hmm.... :-D

Cheers!
SG
 
P

Pavel

SG said:
[...]

template<class C> void foo(C&c) {
assert(!c.empty());
typename C::iterator lastElemIter = --c.end();
... // use lastElemIter here
}

would give me an iterator to the last element. It works if the iterator's
implementation happen to be a class

Not necessarily. operator-- could be implemented as a free function
taking an lvalue reference parameter. And it would be ok to do so
because the ITERATOR CONCEPT only requires ++ and -- (for
bidirectional iterators) to work on LVALUES. We have interfaces for a
reason. Don't rely on specific implementations!

This is essentially what I need semantically. Performance-wise, however, I want
to avoid std::advance, because it may be and often is less efficient for many
iterators (e.g. list or map iterators -- which are usually class object and for
which ++ would work).

These are bidirectional iterators. For such iterators std::advance
maps to something like this via tag dispatching:

template<class Iter>
inline void advance_(
Iter& it,
typename iterator_traits<Iter>::difference_type d,
bidirectional_iterator_tag)
{
if (d<0) {
while (d++< 0) --it;
} else {
while (d--> 0) ++it;
}
}

Compared to ++it, advance(it,1) only requires two additional tests --
that is, unless the compiler inlines this function and applies some
dead branch elimination because the value d is known to be 1 at
compile time during inlining.

Of course, why write advance(it,1) if you can write ++it directly? I
don't know. That's just how the upcoming standard describes the
behaviour of std::next. I guess implementers will simply write this

template<class Iter>
inline Iter next(Iter x) { ++x; return x; }

considering the "as-if rule".

And just for the fun of it, let's ACTUALLY test how G++ optimizes
advance with a constant second parameter of value 1 for list
iterators:

#include<iterator>
#include<list>

typedef std::list<int>::iterator iter;

iter next(iter it) {
std::advance(it,1);
return it;
}

--[ g++ -O3 advance.cpp&& objdump -Cd advance.o ]-->

00000000<next(std::_List_iterator<int>)>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 8b 45 08 mov 0x8(%ebp),%eax
6: 8b 00 mov (%eax),%eax
8: c9 leave
9: c3 ret
a: 90 nop
b: 90 nop

I see no loop, no tests of any kind. In fact, when I replace
advance(it,1) with ++it, I see EXACTLY the same assembly code.
Hmm.... :-D
Yes, I know. This is because ++ is inlined for list::iterator (and then the
implementation uses the benefit of known const argument). For map::iterator it
may not be inline (e.g. it is not in g++ STL, via non-inline
_Rb_tree_increment()). Because a generic algorithm could be applied to both map
and list in different instantiations, you want to use ++ if this is what you mean.

Again, it was just an example of why the uniformness could be useful. My real
question is "what is the reason for not having uniformness; in particular,
whether using wrapper classes is sub-optimal somehow".
Cheers!
SG

-Pavel
 

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

No members online now.

Forum statistics

Threads
473,983
Messages
2,570,187
Members
46,747
Latest member
jojoBizaroo

Latest Threads

Top