简体   繁体   中英

Difference in these methods of Operator overloading in C++

#include<iostream>
using namespace std;
class X
{
    int i;

    public:
    X(int a=0) : i(a) {}

    friend X operator+ (const X& left,const X&right);  

};
X operator+ (const X& left,const X&right)  // Method 1
{
    return X(left.i + right.i);
}

X operator+ (const X& left,const X&right) // Method 2
{
    X temp(left.i + right.i);
    return temp;
}

int main()
{
    X a(2),b(3),c;

    c=a+b;

    c.print();
    return 0;
}

In this Code, Operator + is overloaded via 2 different method.

My Question is What is the difference between these methods and which should be considered more practical to use ?

I can't see a case where any compiler would generate different code between those two versions. The second one is slightly more verbose, but the compiler is allowed to optimize away the notional extra copy in that case and I'm not aware of any compiler that wouldn't do that elision.

That said, this is a micro-optimization: Write the code that's clearest, which then brings me to my final point. Don't write either of these operators, but write the idiomatic version in conjunction with += :

X& operator+=(const X&right) { i += right.i; return *this; }
X operator+(X left, const X& right) { return left += right; }

There is no difference between those two methods, and you should use the one that best communicates its intent for you.

Paragraph 12.8/31 on copy elision specifies:

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization. This elision of copy/move operations, called copy elision , is permitted in the following circumstances (which may be combined to eliminate multiple copies):

— in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type , the copy/move operation can be omitted by constructing the automatic object directly into the function's return value

— [...]

As you can see, both the creation of a temporary and an id-expression naming a local object with automatic storage duration qualify for copy elision.

Moreover, the compiler will treat the local temp like an rvalue (read: like a temporary, in this case) for the purposes of returning it from a function. Paragraph 12.8/32 of the C++11 Standard specifies:

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue . [...]

Because of this, I would strongly suggest removing the const qualification from the return type:

    const X operator + (const X& left, const X&right)
//  ^^^^^
//  Don't use this!

In C++11, this will inhibit move semantics, because you cannot move from a const object, even if it is an rvalue - in short, the move constructor of X , provided one exists, will not be picked, and the copy constructor will be called.

Difference is that Method 1 uses a concept called "RETURN VALUE OPTIMIZATION".

Method 1:

When compiler sees that you have no use for the object it is creating other than to return it. The compiler takes advantage of this and " it build object directly at location of where this value is supposed to be returned to ". here, only one ordinary constructor call is necessary (no copy constructor is required) and there is no destructor call because you never actually created local object. this is more efficient.


Method 2:

First temporary object named temp is created. then copy constructor copies the temp to location of the oustide return value. and then the destructor is called for temp at the end of scope.

Ultimately Method 1 is more efficient but this is compiler dependent feature.

The second implementation will cause NRV optimization. Stan Lippman said NRV optimization needed an explicit copy constructor, but here the class X is simple enough so I don't think NRV needs explicit copy constructor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM