Operator overloading, operator+ vs operator+=

2019-02-26 03:41发布

问题:

I was reading through some c++ source code, and i came over some syntax.

path& path::operator+=(string postPath)

and i was wondering whether it is actual syntax and why c++ is not using the already existing operator+ instead combined with applying the value to the object in question.

Is it like, if you want to make sure that the object gets deleted properly. But the destructor should deal with all of that.

-Edit1

I know there is a difference between a += b; and a + b;
What i was wondering was why does c++ not just use the operator+ with the += instead of having to redefine the operator+= as the same as the operator+

-Edit2

Im not sure it came across correctly, but what i was asking was why the language doesn't infer += based on +. And now i realize the other uses of +=. Thanks everyone :)

回答1:

  1. There may be efficiency concerns; if your object is expensive to copy/assign, a+=b potentially saves you a temporary construction, a copy construction and an assignment, and allow you to better exploit the resources you already have in a target object. If std::vector had a += operator to concatenate vectors, it would be way more efficient to implement it directly (you can exploit the extra capacity of the target object and avoid useless allocations) instead of creating a temporary sum vector (which starts "from scratch") and assigning it.

    Actually, normally I implement + in terms of +=, usually it yields code that is both more efficient and easier to write; like this:

    T &operator+=(const T &r)
    {
        // say that T encapsulates an N-dimensional array
        for(int i=0; i<N; ++i)
            arr+=r.arr[i];
        return *this;
    }
    
    T operator+(const T &r)
    {
        T ret(*this);
        ret+=r;
        return ret;
    }
    

    (although I agree that it would be nice to have a way to ask the compiler to synthesize the +/- from the existing operators; the same for the relational operators)

  2. You may want to have an object that can be added something but cannot be copied/assigned. For example, for a toy project of mine I briefly considered having signal objects (think boost or Qt, or .NET events/multicast delegates) that overloaded += to add a connection (Signal &operator+=(std::function<T...> fn)), but I didn't want to deal with the assignment/copy semantic (that IMHO for a signal doesn't make sense);

  3. At the bottom of it all, there's the general idea that in C++ you can overload (almost) all operators to have them do whatever you want, without particular restrictions of semantics. You can write an operator+ that launches a rocket and an operator+= that deletes all the files on your hard disk - you are in charge, if it makes sense in your application you are free to do it without particular restrictions.



回答2:

C++ makes no assumptions with regards to overloaded operators; you can define an operator+ which is not commutative, for example. And you can define an operator+= which has no relation to the operator+. You can also define an operator+= without defining operator+ or vice versa.

As to why: for starters, you really wouldn't want the compiler to assume that operator+ on strings is commutative, and optimize in consequence. And once having opened the door, the authors of the language no doubt felt that it was best to leave it up to the programmer, rather than to impose anything at language level. Even if I can't think of a case off-hand, there may be cases where it makes sense to support += and + with slightly different semantics. The general philosophy of C++ has always been to give the programmer all of the tools he requires to write good code, but not to ban code which isn't conform to the current idea of what is bad code. (In the long run, this has paid off, since our ideas as to what is good and bad code have evolved.)



回答3:

Yes, path& path::operator+=(string postPath); is valid and overloads the += operator for the case in which a string is added onto a path.

The reason why you want to be able to overload it is simple: operator+ must return a new value instead of changing the old one, while operator+= can reuse existing resource (e.g. allocated memory). Since the major operation of appending strings (which is what you are doing) is memory allocation, a += can be significantly more performant in your exact case.

Additionally, the operation SomePath + SomeString raises the question of SomeString + SomePath, and even worse, SomeStringA + SomePathB, all of which are slightly different, while SomePath += SomeString has a very clear meaning.

Since it shoud now be clear why you want to be able to implement += without implementing +, consider the other direction: Why not just use a = a + b as the default implementation for a += b:

First, the operator overloading rules are older than = delete. Therefore, this rule would always trigger, even in cases where you do not want operator+= to exist at all. Note that implementing the "default" is very simple:

A& operator+=(A const& other) { return *this = *this + other; }


回答4:

why c++ is not using the already existing operator+ instead combined with applying the value

Precisely because the += mutates, and + doesn't. That often implies significant differences in the implementation.



回答5:

Implementing a += b as a = a+b would be less efficient than implementing it directly, since it would have to create and destroy the temporary object that's assigned to a.

It's more efficient to implement + in terms of +=

path operator+(path prePath, string postPath) {
    return prePath += postPath;
}

Philosophically, one might argue that it's less surprising if the language doesn't magically generate operators that you might not expect. Many people are caught out by implicitly-generated constructors and assignment operators giving their types invalid copy semantics (until they learn the Rule of Three), and other magical behaviour might cause confusion in other ways.