1

When writing f(x++), we mean f(x);++x; Yet the operator for an object is usually written as

foo operator++(int) {
    foo temp = *this;
    ++*this;
    return temp;
}

Can I make it works like

const foo operator++(int) {
    return *this;
    // when this code done
    ++this;
}

? (A strong reason is that some users are more used to x++ than ++x, and for an object the usual solution costs a copy constructing and a deconstructing; another is that sometimes x++ matches the meaning more than x;++x)

This solution works in the environment sometimes, but fail sometimes, don't work with auto and may rely on UB. Is there better solution?

l4m2
  • 1,157
  • 5
  • 17
  • Possible duplicate of [C++: overloading ++ for both pre and post increment](https://stackoverflow.com/questions/15244094/c-overloading-for-both-pre-and-post-increment) – Mikhail Mar 13 '19 at 03:08
  • 1
    `foo operator++(int) = delete;` so they're forced to use pre-increment. – Jonathan Potter Mar 13 '19 at 03:12
  • @JonathanPotter Another reason is sometimes `x++` matches the meaning more than `x;++x` – l4m2 Mar 13 '19 at 03:38

1 Answers1

2

You can do that if you use a helper class whose destructor takes care of the ++(*this); part.

struct IncrementMinder
{
    IncrementMinder(foo* fPtr) : fPtr_(fPtr) {}
    ~IncrementMinder() { ++(*fPtr_); }
    foo* fPtr_;
}

foo operator++(int) {
    InrementMinder minder(this);
    return *this;
    // Destructor of minder takes care of ++(*this)
}

I think your test is not properly framed. A better demonstration of the concept is as below:

#include <iostream>

struct foo {

   struct IncrementMinder
   {
      IncrementMinder(foo* fPtr) : fPtr_(fPtr) {}
      ~IncrementMinder() { ++(*fPtr_); }
      foo* fPtr_;
   };

   foo(int val) : value(val) {}

   // Not correct.
   // When a reference is returned, const or otherwise, the calling function
   // will get a reference to the object, which will be incremented by the
   // time the reference is used in the calling function.
   // const foo& operator++(int) {

   foo operator++(int) {
      IncrementMinder minder(this);
      return *this;
      // Destructor of minder takes care of ++(*this)
   }

   foo& operator++() {
      ++value;
      return *this;
   }

   operator int() {
      return 0;
   }

   int value;


} bar{20};

void f(const foo& bar) { std::cout << "bar.value: " << bar.value << "\n"; }

int main()
{
   f(bar);

   std::cout << "Using post-increment...\n";

   f(bar++);
   f(bar);;

   std::cout << "Using pre-increment...\n";

   f(++bar);
   f(bar);
}

Output with g++ -std=c++14:

bar.value: 20
Using post-increment...
bar.value: 20
bar.value: 21
Using pre-increment...
bar.value: 22
bar.value: 22

Live Demo.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Does the destruction happen at the expected time? – l4m2 Mar 13 '19 at 03:21
  • @l4m2, yes it does. – R Sahu Mar 13 '19 at 03:22
  • [Tested](https://tio.run/##fZDBTsMwEETv/opVkWgSC5VzHHHiwgGJD6hUGccBC2JH9oZLFH49rJ000KolF8fjmbdjq667e1Nqmm6MVZ99raEyLqDXsn1gjH56hdA4B8O6e7LK61ZbfDa21p4NDOg7UzPKFNC8oM@hTOshm3fDmPzf5wE6Ac6zInlzAbNtxRwEGwVjytmQCt2C67SX6DyFjEWKX@oB7UzHdxNykRxeY@8tFFGald0OHvV8O@fBNUsIUH7oAEp6HcVYLmHYeK3HsUTAuiyV6xGqCjYmVpJB13u7uVSBcEcG0E1WyuK6T44RXqUX7MuZGprsz3iS49OdjuyXafSKjJDQSmNXbpPFjDiNbPd2K36POf/PwPlVwjhNPw) and increment still happen before use – l4m2 Mar 13 '19 at 03:30
  • [This one](https://tio.run/##jZCxboMwEIZ3P8UpkRoHt1JnjLp3iNQHyEJt01oqNjJHF@S@Oj2bhBKGqCzmfP///edTXff0odQ07a1TX4M2UFnfYzB1@8IY/QwKofEexqV6dSqY1jg8WadNYCMD@khTQPOGQeZyI@JL@whlPvlcjDHLf7Z66oAQvMgqCbPKdybU6EMKeyCJ8q5HGIPBITjIWhlZlIzNnQ108RPYOqSITL3YtxPgp@2PksUrLGWuCVd7j7oslR8Qqgp2NlHq3uiz28k1vki8jFteQTPwzRDPWRHhvaY9fnuroeGreLpOi7mNHC5ptCRGSGhr6xZuw5NH3loOZ3eQf20h7gmE@Bfh8T4rTtMv) works in usual cases but not in one line ordered, not sure if it's UB(no for an int) – l4m2 Mar 13 '19 at 03:34
  • You still copy and destruct the class when returning the value – l4m2 Mar 13 '19 at 06:16
  • @l4m2, I don't think you can avoid that for a class. Was that your main concern? – R Sahu Mar 13 '19 at 06:19
  • Your solution does exactly what the first code in problem do [1](https://t%49nyurl.com/y5gxal5o) [2](https://t%49nyurl.com/y2l2bvug) – l4m2 Mar 13 '19 at 06:24
  • @l4m2, I am not surprised. My answer does not take away the construction and destruction of the object. I didn't mean to mislead you to think that it did. I apologize if I mislead you. – R Sahu Mar 13 '19 at 16:53
  • 1
    I make plenty use of "scoped constructs" such as this...... though I'm not convinced it's warranted in this case. Wonder how much it really saves ya. – Lightness Races in Orbit Mar 13 '19 at 17:40
  • You could do it "cheaply" with a construct that invokes a lambda on scope exit, where said lambda has a ref capture and performs the increment. But that might _still_ cost you the storage of a reference, in theory. – Lightness Races in Orbit Mar 13 '19 at 17:41
  • @LightnessRacesinOrbit, `IncrementMinder` would be justified only if: 1. You make it a class template, and 2. Use it in a few more places. – R Sahu Mar 13 '19 at 17:46