The difference between pre-++ and post-++ operator overloading (detailed)

Difference between pre++ and post++ operator overloading

int a = 0;
++ a;   //前置++
a++;    //后置++

"C Expert Programming" has the following description (P276, People's Posts and Telecommunications Press):
++a means to take the address of a, increase its content, and then put the value in the register;

a++ means to take the address of a, load its value into a register, and then increase the value of a in memory;

In addition, I found an article on the Internet to discuss their differences from the perspective of operator overloading, as follows:

Suppose there is a class Age that describes age. This class overloads two operators, pre-++ and post-++, to realize self-increment of age.

class Age   
{   
public:   
  
    Age& operator++() //前置++   
    {   
        ++i;   
        return *this;   
    }   
  
    const Age operator++(int) //后置++   
{   
        Age tmp = *this;   
        ++(*this);  //利用前置++   
        return tmp;   
    }   
  
    Age& operator=(int i) //赋值操作   
    {   
        this->i = i;   
        return *this;   
    }   
  
private:   
    int i;   
};  

From the above code, we can see that there are several differences between pre-++ and post-++:

Different return types, different
formal parameters,
different codes,
different efficiencies, and
differences in return value types

The return type of pre-++ is Age&, and the return type of post-++ is const Age. This means that pre-++ returns an lvalue and post-++ returns an rvalue. (There's a lot of discussion about lvalues ​​and rvalues, see below this article)

Lvalues ​​and rvalues ​​determine the usage of pre-++ and post-++.

int main()   
{   
    Age a;   
  
    (a++)++;  //编译错误   
    ++(a++);  //编译错误   
    a++ = 1;   //编译错误   
    (++a)++;  //OK   
    ++(++a);  //OK   
    ++a = 1;   //OK   
}  

The type of ++ is const Age, so operations such as pre-++, post-++, and assignment cannot be performed on it.

The type of ++a is Age&, of course it can be pre-++, post-++, assignment and other operations

Why is the return type of a++ a const object?

There are two reasons:

If it is not a const object, expressions like a(++)++ can be compiled. However, the effect is counterintuitive. a is actually only increased by 1, because the second increment acts on a temporary object.
In addition, for built-in types, expressions like (i++)++ cannot be compiled. Operator overloading for custom types should behave the same as built-in types.
If the return type of a++ is changed to a non-const object, it will definitely pass compilation, but we'd better not do this.

Why is the return type of ++a a reference?

The reason for this should be: to be consistent with the behavior of built-in types. Prepending ++ always returns the object itself that was incremented. Thus, the effect of ++(++a) is that a is incremented twice.

The difference between formal parameters

Pre-++ has no parameters, and post-++ has an int parameter, but that parameter is not used either. Very strange, is there any special purpose?

In fact, there is no special purpose, just to bypass the grammatical restrictions.

The operator overloading functions of pre-++ and post-++ must have different function prototypes. Otherwise, it violates the grammatical rule that "overloaded functions must have different function prototypes".

Although the return type of pre-++ and post-++ is different, the return type does not belong to the function prototype. In order to bypass the grammatical restrictions, we had to add an int parameter to the post ++.

The reason is that simple, there is really no other special purpose. In fact, it is also possible to add a formal parameter to the front ++; it is also possible to add a double parameter instead of an int parameter. It's just that it was decided at the time.

The difference in code implementation

The implementation of the front ++ is relatively simple. After the self-increment, just return this. It should be noted that this must be returned.

The implementation of Post++ is a little more cumbersome. Because we want to return the object before the auto-increment, we first copy the object, then perform the auto-increment, and finally return that copy.

In Age's code, post ++ utilizes pre ++ to achieve auto-increment. This is done to avoid duplication of "auto-increment code".

In this example, the self-increment code is very simple, just one line of ++i, there is no need to do this. But in other examples with complex auto-increment logic, it is still necessary to do so.

The difference in efficiency

If there is no need to return the value before the increment, then the calculation effect of pre-++ and post-++ is the same. However, we should still prefer to use prefix ++, especially for auto-increment operations of user-defined types.

Pre-++ is more efficient, the reason is: post-++ will generate temporary objects.

This can also be seen from the code implementation of Age's post-post ++.

const Age operator++(int) //后置++   
	{
    
       
	    Age tmp = *this;   
	    ++(*this);  //利用前置++   
	    return tmp;   
	}

Obviously, tmp is a temporary object, which will cause additional overhead of a constructor and a destructor. Although, the compiler can optimize away these overheads in some cases. However, we'd better not rely on the behavior of the compiler.

Therefore, when it is not a built-in type, try to use pre-++, because of high efficiency (post-increment, low efficiency)

Original link: https://blog.csdn.net/randyjiawenjie/article/details/6747720

Guess you like

Origin blog.csdn.net/SFDWU3QVG/article/details/125715842