Topic: Post-increment operator


Author: David R Tribble <david@tribble.com>
Date: 2000/08/16
Raw View
Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
> [...]
>> Indeed, the postfix operator usualy returns an object, not
>> a reference.

thp@roam-thp2.cs.ucr.edu wrote:
> I've always thought that the C++ idiom is that:
>   --  postfix-++ returns the incremented object's previous rvalue
>   --  prefix-++ appears to return the incremented object itself by
>       actually returning a reference to that object.

I would say that you would want to return a const reference for
prefix-++, unless you want to allow strange code such as

    (++a)++;
    ++(++b);

> How would one return an "object" except by reference?

You could return an rvalue instead of a reference, but this is
less efficient than returning a [const] reference for non-primitive
types.

--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: <thp@roam-thp2.cs.ucr.edu>
Date: 2000/08/16
Raw View
David R Tribble <david@tribble.com> wrote:
> Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
>> [...]
>>> Indeed, the postfix operator usualy returns an object, not
>>> a reference.

> thp@roam-thp2.cs.ucr.edu wrote:
>> I've always thought that the C++ idiom is that:
>>   --  postfix-++ returns the incremented object's previous rvalue
>>   --  prefix-++ appears to return the incremented object itself by
>>       actually returning a reference to that object.

> I would say that you would want to return a const reference for
> prefix-++, unless you want to allow strange code such as

>     (++a)++;
>     ++(++b);

>> How would one return an "object" except by reference?

> You could return an rvalue instead of a reference, but this is
> less efficient than returning a [const] reference for non-primitive
> types.

For C++, the ARM (and following it the C++ Standard) contains some
strange wording regarding the result of the assignment operator:

   The result of the assignment operation is the value stored in the
   left operand after the assignment has taken place; the result is an
   lvalue

Similarly for the prefix-++ operator, the ARM says:

   The operand must be a modifiable lvalue. ... The value is the new
   value of the operand; it is an lvalue.

Given that the distinction between objects and their content is
fundamental to the underlying model of computation the above wording
is visibily inconsistent at least in the case of built-in types.

   Every expression is either an lvalue or an rvalue.  [C++ Standard 3.10]

So, why the deviation from C semantics?  Probably to allow the uniform
handling of built-in and user-defined types, such as class types, where
the distinction between rvalue and lvalue gets obscure:

   An lvalue refers to an object or a function. Some rvalue
   expressions -- those of class or cv-qualified class type -- also
   refer to objects.  [C++ Standard 3.10]

The most sensible interpretation that I can find is that the result is
the lvalue of, i.e., a reference to, the object designated by the
lvalue operand, whose new rvalue can be obtained via implicit
lvalue-to-rvalue conversion.  That interpretation is upward compatible
from C and allows as well-formed:

  - non-C expressions, like (a=b)=c, wherein the ancestral second
    assignment modifies a while it is undergoing modification (unless
    a is of user-defined type), a violation of safety that invokes
    undefined behavior.

  - C expressions, like a=b=c and a=++b, wherein the first-evaluated
    expression yields b's lvalue, which is automatically converted to
    b's rvalue and assigned to a, which is different behavior from C
    in cases where b is volatile and lvalue-to-rvalue conversion is
    implementation defined to involve read access to the object
    designated by the lvalue.  In other cases, the as-if rule allows
    that fetch to be optimized away.

  - non-C expressions, like j=(&++a[0])[i], wherein the ancestral
    second subscripting operation yields the lvalue of a[i], which
    gets lvalue-to-rvalue converted to the value of a[i] while a[0] is
    undergoing modification (unless the elements of a are of user-
    defined type).  So, when i is zero, the implementation must wait
    while the value of a[0] stabilizes.  In either case, however, the
    behavior and value are well defined.

Note that the wording from the ARM does not explicitly say that the
resulting lvalue must be that of the object designated by the lvalue
operand -- it could for instance be that of a temporary that also
holds the new rvalue.  But then the subsequent assignment attempts to
read that temporary gets accessed while it is undergoing modification.

Tom Payne

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 2000/08/09
Raw View
In article <398F42E7.DED714E4@tribble.com>, David R Tribble
<david@tribble.com> writes
>Francis Glassborow wrote:
>> But that means that:
>>
>>   mytype & foo(mytype & something){
>>
>>   // code
>>       return something++;
>>   }
>>
>> will fail. I think that might be quite surprising if I was using
>> yourtype and had not realised that you eschewed the standard idiom.
>
>You are correct.  But my argument still stands for operator=().

Well, actually I think I wasn't :) Post-increment and pre-increment are
necessarily handled differently.


Francis Glassborow      Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: <thp@roam-thp2.cs.ucr.edu>
Date: 2000/08/09
Raw View
Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
[...]
> Indeed, the postfix operator usualy returns an object, not
> a reference.

I've always thought that the C++ idiom is that:
  --  postfix-++ returns the incremented object's previous rvalue
  --  prefix-++ appears to return the incremented object itself by
      actually returning a reference to that object.

How would one return an "object" except by reference?

Tom Payne

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Ron Natalie <ron@sensor.com>
Date: 2000/08/09
Raw View

thp@roam-thp2.cs.ucr.edu wrote:
>
> How would one return an "object" except by reference?
>

By value.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: <thp@roam-thp2.cs.ucr.edu>
Date: 2000/08/10
Raw View
Ron Natalie <ron@sensor.com> wrote:


> thp@roam-thp2.cs.ucr.edu wrote:
>>
>> How would one return an "object" except by reference?
>>

> By value.

"An OBJECT is a region of storage." [1.3]  VALUES are what
objects hold.

Tom Payne

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: David R Tribble <david@tribble.com>
Date: 2000/08/08
Raw View
David R Tribble <david@tribble.com> writes
>> ... it is generally a good idea to return a const reference:
>>
>>    const Type &  operator ++(int);
>>
>> This prevents strange code like my example above, in spite of the
>> fact that C++ generally encourages returning non-const references
>> for operator++() and operator=().

Francis Glassborow wrote:
> But that means that:
>
>   mytype & foo(mytype & something){
>
>   // code
>       return something++;
>   }
>
> will fail. I think that might be quite surprising if I was using
> yourtype and had not realised that you eschewed the standard idiom.

You are correct.  But my argument still stands for operator=().

--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 2000/08/04
Raw View
In article <398995DD.98285953@tribble.com>, David R Tribble
<david@tribble.com> writes
>Scott Meyers wrote:
>> Yes.  For details, consult More Effective C++, Item 6.
>
>Yes, unless you want to allow strange things like
>
>    (a++)++;
>
>it is generally a good idea to return a reference.
>
>And (in disagreement with Scott), it is generally a good idea to
>return a const reference:
>
>    const Type &  operator ++(int);
>
>This prevents strange code like my example above, in spite of the
>fact that C++ generally encourages returning non-const references
>for operator++() and operator=().

But that means that:

mytype & foo(mytype & something){

// code
    return something++;
}

will fail. I think that might be quite surprising if I was using
yourtype and had not realised that you eschewed the standard idiom.


Francis Glassborow      Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: jpotter@falcon.lhup.edu (John Potter)
Date: 2000/08/04
Raw View
On Thu,  3 Aug 2000 16:46:53 GMT, David R Tribble <david@tribble.com>
wrote:

> Chris Newton wrote:
> >> But seriously, am I right in thinking that in general, postfix ++
> >> normally returns an rvalue, and hence for classes it wouldn't
> >> normally return a reference?
>
> Scott Meyers wrote:
> > Yes.  For details, consult More Effective C++, Item 6.
>
> Yes, unless you want to allow strange things like
>
>     (a++)++;
>
> it is generally a good idea to return a reference.

Now, I'm confused.  But, I think it is really your words.

Chris said, value?
Scott said, yes (++plug ;)
You said, yes reference

> And (in disagreement with Scott), it is generally a good idea to
> return a const reference:

No interest in reopening that const can of worms.  No comment.

>     const Type &  operator ++(int);
>
> This prevents strange code like my example above, in spite of the
> fact that C++ generally encourages returning non-const references
> for operator++() and operator=().

But the subject is "normal" operator++(int).  Since it usually
returns the old value of the object and increments the object, to
what are you returning a reference?

Assuming that we are really returning a value, you can prevent the
above silly code with either of

   Type const Type::operator++ (int);
   Type operator++ (Type&, int);

The strange ostream_iterator OTOH only has one real operation,
operator=(T const&).  Since iterators must support some
other operations, it uses a proxy to simulate them.  The proxy is
itself returned by reference from all of those no-ops.

John

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Herb Sutter <hsutter@peerdirect.com>
Date: 2000/08/05
Raw View
Francis Glassborow <francis@robinton.demon.co.uk> writes:
>In article <398995DD.98285953@tribble.com>, David R Tribble
><david@tribble.com> writes
>>Yes, unless you want to allow strange things like
>>    (a++)++;
>>it is generally a good idea to return a reference.
>>
>>And (in disagreement with Scott), it is generally a good idea to
>>return a const reference:
>>    const Type &  operator ++(int);

I don't understand. Postfix increment should always return a value. The
canonical implementation of postfix ++ is:

  inline T T::operator++(int)
  {
    T old( *this ); // remember our original value
    ++*this;        // always implement postincrement
                    //  in terms of preincrement
    return old;     // return our original value
  }

That specifically prevents subtle errors like a++++, which can never be
right/useful (unless you override postfix ++ to use other than ordinary
semantics, which would be even more evil).

>>This prevents strange code like my example above, in spite of the
>>fact that C++ generally encourages returning non-const references
>>for operator++() and operator=3D().

Postfix increment should always return a value. PREFIX increment and all
assignments should return non-const references -- see Exceptional C++,
Item 41 sidebar (pg 166), and GotW #23 footnote 3
(http://www.peerdirect.com/resources/gotw023a.html). From the PeerDirect
coding standards:

=B7 declare copy assignment as "T& T::operator=3D(const T&)"
  =B7 never return const T&; although this would be nice since it prevent=
s
usage like "(a=3Db)=3Dc", it would mean that for example you couldn't
portably put T objects into standard library containers, since these
require that assignment returns a plain T& (Item 41; see also Cline95:
212; Murray93: 32-33)

>But that means that:
>
>mytype & foo(mytype & something){
>
>// code
>    return something++;
>}
>
>will fail. I think that might be quite surprising if I was using
>yourtype and had not realised that you eschewed the standard idiom.

Yes, that code should always fail to compile. It's a logic error.

Herb

---
Herb Sutter (mailto:hsutter@peerdirect.com)

CTO, PeerDirect Inc. (http://www.peerdirect.com)
Chair, ANSI SQL Part 12: SQL/Replication
Contributing Editor, C/C++ Users Journal (http://www.cuj.com)

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Dennis Yelle <dennis51@jps.net>
Date: 2000/07/29
Raw View
Chris Newton wrote:
>
> Dear all,
>
> The following line appears in "The C++ Programming Language, 3rd Ed",
> page 558, in the discussion of ostream_iterator:
>   ostream_iterator& operator++(int);

ostream_iterator::operator++() does not actually increment anything,
all it does is: return *this.
That is why it can return a referance instead of an object.

Dennis Yelle
--
I am a computer programmer and I am looking for a job.
There is a link to my resume here:  http://table.jps.net/~vert

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Chris Newton" <chrisnewton@no.junk.please.btinternet.com>
Date: 2000/08/01
Raw View
Dennis Yelle <dennis51@jps.net> wrote...
> ostream_iterator::operator++() does not actually increment
> anything, all it does is: return *this.

As indeed does the postfix form, ostream_iterator::operator++(int),
apparently. Moral for the day: check the standard first! :-)

But seriously, am I right in thinking that in general, postfix ++
normally returns an rvalue, and hence for classes it wouldn't normally
return a reference? Having established that ostream_iterator's
implementation must just return *this, I can understand that a special
case was made there, although I don't quite see what returning a
reference adds to the usual idiom. But after replies from a couple of
experts recently, I'm questioning whether my understanding of this whole
area isn't flawed somewhere along the line.

Cheers,
Chris


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: jpotter@falcon.lhup.edu (John Potter)
Date: 2000/08/01
Raw View
On Sat, 29 Jul 2000 03:39:30 CST, "Chris Newton"
<chrisnewton@no.junk.please.btinternet.com> wrote:

> Dear all,
>
> The following line appears in "The C++ Programming Language, 3rd Ed",
> page 558, in the discussion of ostream_iterator:
>   ostream_iterator& operator++(int);
>
> I was sufficiently surprised to see a postfix ++ returning a reference
> that I actually mailed the author to ask if this was correct. He
> replied, telling me that not only is it correct, it is also typical for
> a post-increment to return an lvalue, and hence the usage is also
> colloqual.

I will assume that the universe of discussion was output iterators, not
all post-increment operators.

> I confess to being confused. I would have expected the prefix form to
> return a reference, but not the postfix. 5.2.6/1 of the standard seems
> to say that the result of a postfix ++ is an rvalue. I do not wish to
> hassle Bjarne if I'm going slightly mad, but could anyone explain this
> to me?

Output_iterators are strange ducks.

If you check the requirements, you will find that they are very
underspecified.  About the only thing that you can do is to use
a sequence of operations equivalent to (*ot = value, ++ ot).

If you check the requirements for ostream_iterator, you will find
that they are very overspecified.  The following are all identical.

char p[] = "Hello";
ostream_iterator<char> ot(cout);
for (char* it = p; *it; ++ it)

   *ot = *it;
   ++ ot;

   *ot = *it; // skip the increment

   * ++ ++ ot ++ ++ = *it; // do a bunch of increments

   ot = *it;  // skip the dereference
   ++ ot;

   ot = *it; // skip all of those no-ops

I once wrote a buffered ostream_iterator in which the increment did
the write while the assignment only filled the buffer.  It gave the
same results as the standard ostream_iterator in the first case only.
It was a valid standard output_iterator but not a valid standard
ostream_iterator.

John

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: smeyers@aristeia.com (Scott Meyers)
Date: 2000/08/01
Raw View
On Tue, 1 Aug 2000 00:25:39 CST, Chris Newton wrote:
> But seriously, am I right in thinking that in general, postfix ++
> normally returns an rvalue, and hence for classes it wouldn't normally
> return a reference?

Yes.  For details, consult More Effective C++, Item 6.

Scott

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Chris Newton" <chrisnewton@no.junk.please.btinternet.com>
Date: 2000/07/29
Raw View
Dear all,

The following line appears in "The C++ Programming Language, 3rd Ed",
page 558, in the discussion of ostream_iterator:
  ostream_iterator& operator++(int);

I was sufficiently surprised to see a postfix ++ returning a reference
that I actually mailed the author to ask if this was correct. He
replied, telling me that not only is it correct, it is also typical for
a post-increment to return an lvalue, and hence the usage is also
colloqual.

I confess to being confused. I would have expected the prefix form to
return a reference, but not the postfix. 5.2.6/1 of the standard seems
to say that the result of a postfix ++ is an rvalue. I do not wish to
hassle Bjarne if I'm going slightly mad, but could anyone explain this
to me?

Thanks,
Chris


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 2000/08/03
Raw View
Chris Newton wrote:

> The following line appears in "The C++ Programming Language, 3rd Ed",
> page 558, in the discussion of ostream_iterator:
>   ostream_iterator& operator++(int);
>
> I was sufficiently surprised to see a postfix ++ returning a reference
> that I actually mailed the author to ask if this was correct. He
> replied, telling me that not only is it correct, it is also typical for
> a post-increment to return an lvalue, and hence the usage is also
> colloqual.
>
> I confess to being confused. I would have expected the prefix form to
> return a reference, but not the postfix.

Indeed, the postfix operator usualy returns an object, not
a reference. ostream_iterator is the exception rather than
the norm. (ostream_iterator::operator (int) could also
return an ostream_iterator; it isn't really important.)

--

Valentin Bonnard

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: David R Tribble <david@tribble.com>
Date: 2000/08/03
Raw View
Chris Newton wrote:
>> But seriously, am I right in thinking that in general, postfix ++
>> normally returns an rvalue, and hence for classes it wouldn't
>> normally return a reference?

Scott Meyers wrote:
> Yes.  For details, consult More Effective C++, Item 6.

Yes, unless you want to allow strange things like

    (a++)++;

it is generally a good idea to return a reference.

And (in disagreement with Scott), it is generally a good idea to
return a const reference:

    const Type &  operator ++(int);

This prevents strange code like my example above, in spite of the
fact that C++ generally encourages returning non-const references
for operator++() and operator=().

--
David R. Tribble, mailto:david@tribble.com, http://david.tribble.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]