Why not overload operator+=() for std::vector?

2019-01-27 12:18发布

问题:

I've started learning C++, so I don't know in my lack of knowledge/experience why something so seemingly simple to a rookie as what I'm about to describe isn't already in the STL. To add a vector to another vector you have to type this:

v1.insert(v1.end(), v2.begin(), v2.end());

I'm wondering whether in the real world people just overload the += operator to make this less verbose, for example to the effect of

template <typename T>
void operator+=(std::vector<T> &v1, const std::vector<T> &v2) {
    v1.insert(v1.end(), v2.begin(), v2.end());
}

so then you can

v1 += v2;

I also have this set up for push_back to "+=" a single element to the end. Is there some reason these things should not be done or are specifically avoided by people who are proficient in C++?

回答1:

This is actually a case where I would like to see this functionality in the form of an overload of append(). operator+= is kinda ambiguous, do you mean to add the elements of each vector to each other? Or you mean to append?

However, like I said, I would have welcomed: v1.append(v2); It is clear and simple, I don't know why it isn't there.



回答2:

I think the main reason is that the semantics of += aren't obvious. There's the meaning that you have here, but there's also an equally valid meaning, which is element-wise addition of each element of equal-sized vectors. Due to this ambiguity I assume they decided it was better to rely on the user to call insert diretly.



回答3:

Operators should be overloaded only when you are not changing the meaning of those operators.*

What that means is, for example, if there is no mathematical definition of the product of two objects, don't overload the multiplication operator for those objects. If there was a mathematical correspondence, operators overloading can make a class more convenient to use by allowing equations to be expressed in the form a*b + c rather than the more verbose (a.multiply(b)).add(c) Where addition and multiplication operators are used, addition and multiplication should be the intent. Any other meaning is more than likely to confuse others. Some other types where overloading operators is acceptable (and, in my opinion, preferable) are smart pointers, iterators, complex numbers, vectors, and bignums.

This follows from one of the design goals of C++, that it should be possible to define classes that are as easy to use as built in types. Of course there are operators you can define on classes which are not mathematical concepts either. You may wish to overload the == and != operators instead of writing an isEqual method, and might want to overload = because the compiler's default assignment operator is not what you want.

On the other hand, overloading an operator to do something unexpected, like defining ^ to translate a string to Japanese, is obscure and dangerous. Your fellow programmers will not be happy to find out that what looked like an exclusive or comparison was actually something very different. The solution then is to write your classes to make it easy to write clear and maintainable code, whether that means using operator overloading or avoiding it.

Adding two vectors is too ambiguous to warrent defining an operator. As others have shown, many people have different ideas of what this means, whereas for a string it is universally understood that adding two strings together means concatenation. In your example, it isn't entirely clear whether you want to do a component wise add on all the elements, add an element to the end, or concat two vectors together. Although it may be more concise to do it that way, using operator overloading to create your own programming language isn't the best way to go.

*Yes, I know Stroustrup overloaded << and >> to do stream operations rather than bitshifts. But those weren't used often compared to arithmetic and pointer operators in the first place, and it could be argued that now that everyone knows how to use cout, it's generally understood that << and >> are the inserter and extractor operators. (He originally tried to use just < and > for input and output, but the meaning of those operators was so ingrained in everyone's minds that the code was unreadable.)



回答4:

In addition to what others mentioned about this syntax not being intuitive and therefore error prone, it also goes against a good design rule making general algorithms applied to various containers free functions, and container specific algorithms -- member functions. Most containers follow this rule, except std::string, which got a lot of flack from Herb Sutter for its monolithic design.