2255

Note: The answers were given in a specific order, but since many users sort answers according to votes, rather than the time they were given, here's an index of the answers in the order in which they make the most sense:

(Note: This is meant to be an entry to Stack Overflow's C++ FAQ. If you want to critique the idea of providing an FAQ in this form, then the posting on meta that started all this would be the place to do that. Answers to that question are monitored in the C++ chatroom, where the FAQ idea started in the first place, so your answer is very likely to get read by those who came up with the idea.)

Community
  • 1
  • 1
sbi
  • 204,536
  • 44
  • 236
  • 426
  • 67
    If we're going to continue with the C++-FAQ tag, this is how entries should be formatted. – John Dibling Dec 14 '10 at 19:45
  • I've written a short series of articles for the german C++ community about operator overloading: [Part 1: operator overloading in C++](http://magazin.c-plusplus.de/artikel/%DCberladung%20von%20Operatoren%20in%20CPlusPlus%20%28Teil%201%29) covers semantics, typical usage and specialities for all operators. It has some overlappings with your answers here, nevertheless there is some additional information. Parts 2 and 3 make an tutorial for using Boost.Operators. Would you like me to translate them and add them as answers? – Arne Mertz Apr 09 '13 at 14:11
  • Oh, and an English translation is also available: [the basics](https://arne-mertz.de/2015/01/operator-overloading-the-basics/) and [common practice](https://arne-mertz.de/2015/01/operator-overloading-common-practice/) – Arne Mertz Jul 31 '17 at 14:13
  • The address-of operator `operator&` is missing. – Red.Wave Jan 19 '21 at 12:36
  • @Red.Wave: Actually, there's a sentence, even in its own paragraph, at the end of the common operator answer, but it says "don't do this". I think it was Pete Becker of Dinkumware (the company which made the std lib later bought by Microsoft) who once said that those who overload `operator&()` and then expect the resulting types to work with the standard library should be forced to implement a std lib which performs this miracle. IOW, if you think you have an application for overloading this operator, I'd be curious to hear it. (Don't hold your breath waiting for applause, though.) – sbi Mar 30 '21 at 20:25
  • @sbi: whether or not to do it is left to the programmer. As long as the **addressof operator** is overloadable, it need be placed on the list. You can put the **don't** recommendation properly in the explanation; but totally omitting it is IMO not a good choice. – Red.Wave Apr 01 '21 at 17:55
  • @Red.Wave: It "needs to be" addressed _where_, exactly? It's on the list of operators that _can_ be overloaded, and it's even mentioned in the answer that lists _commonly overloaded_ operators – even though it is _not_ commonly overloaded. ¯\_(ツ)_/¯ – sbi Apr 14 '21 at 08:08

7 Answers7

1108

Common operators to overload

Most of the work in overloading operators is boiler-plate code. That is little wonder, since operators are merely syntactic sugar, their actual work could be done by (and often is forwarded to) plain functions. But it is important that you get this boiler-plate code right. If you fail, either your operator’s code won’t compile or your users’ code won’t compile or your users’ code will behave surprisingly.

Assignment Operator

There's a lot to be said about assignment. However, most of it has already been said in GMan's famous Copy-And-Swap FAQ, so I'll skip most of it here, only listing the perfect assignment operator for reference:

X& X::operator=(X rhs)
{
  swap(rhs);
  return *this;
}

Bitshift Operators (used for Stream I/O)

The bitshift operators << and >>, although still used in hardware interfacing for the bit-manipulation functions they inherit from C, have become more prevalent as overloaded stream input and output operators in most applications. For guidance overloading as bit-manipulation operators, see the section below on Binary Arithmetic Operators. For implementing your own custom format and parsing logic when your object is used with iostreams, continue.

The stream operators, among the most commonly overloaded operators, are binary infix operators for which the syntax specifies no restriction on whether they should be members or non-members. Since they change their left argument (they alter the stream’s state), they should, according to the rules of thumb, be implemented as members of their left operand’s type. However, their left operands are streams from the standard library, and while most of the stream output and input operators defined by the standard library are indeed defined as members of the stream classes, when you implement output and input operations for your own types, you cannot change the standard library’s stream types. That’s why you need to implement these operators for your own types as non-member functions. The canonical forms of the two are these:

std::ostream& operator<<(std::ostream& os, const T& obj)
{
  // write obj to stream

  return os;
}

std::istream& operator>>(std::istream& is, T& obj)
{
  // read obj from stream

  if( /* no valid object of T found in stream */ )
    is.setstate(std::ios::failbit);

  return is;
}

When implementing operator>>, manually setting the stream’s state is only necessary when the reading itself succeeded, but the result is not what would be expected.

Function call operator

The function call operator, used to create function objects, also known as functors, must be defined as a member function, so it always has the implicit this argument of member functions. Other than this, it can be overloaded to take any number of additional arguments, including zero.

Here's an example of the syntax:

class foo {
public:
    // Overloaded call operator
    int operator()(const std::string& y) {
        // ...
    }
};

Usage:

foo f;
int a = f("hello");

Throughout the C++ standard library, function objects are always copied. Your own function objects should therefore be cheap to copy. If a function object absolutely needs to use data which is expensive to copy, it is better to store that data elsewhere and have the function object refer to it.

Comparison operators

The binary infix comparison operators should, according to the rules of thumb, be implemented as non-member functions1. The unary prefix negation ! should (according to the same rules) be implemented as a member function. (but it is usually not a good idea to overload it.)

The standard library’s algorithms (e.g. std::sort()) and types (e.g. std::map) will always only expect operator< to be present. However, the users of your type will expect all the other operators to be present, too, so if you define operator<, be sure to follow the third fundamental rule of operator overloading and also define all the other boolean comparison operators. The canonical way to implement them is this:

inline bool operator==(const X& lhs, const X& rhs){ /* do actual comparison */ }
inline bool operator!=(const X& lhs, const X& rhs){return !operator==(lhs,rhs);}
inline bool operator< (const X& lhs, const X& rhs){ /* do actual comparison */ }
inline bool operator> (const X& lhs, const X& rhs){return  operator< (rhs,lhs);}
inline bool operator<=(const X& lhs, const X& rhs){return !operator> (lhs,rhs);}
inline bool operator>=(const X& lhs, const X& rhs){return !operator< (lhs,rhs);}

The important thing to note here is that only two of these operators actually do anything, the others are just forwarding their arguments to either of these two to do the actual work.

The syntax for overloading the remaining binary boolean operators (||, &&) follows the rules of the comparison operators. However, it is very unlikely that you would find a reasonable use case for these2.

1 As with all rules of thumb, sometimes there might be reasons to break this one, too. If so, do not forget that the left-hand operand of the binary comparison operators, which for member functions will be *this, needs to be const, too. So a comparison operator implemented as a member function would have to have this signature:

bool operator<(const X& rhs) const { /* do actual comparison with *this */ }

(Note the const at the end.)

2 It should be noted that the built-in version of || and && use shortcut semantics. While the user defined ones (because they are syntactic sugar for method calls) do not use shortcut semantics. User will expect these operators to have shortcut semantics, and their code may depend on it, Therefore it is highly advised NEVER to define them.

Arithmetic Operators

Unary arithmetic operators

The unary increment and decrement operators come in both prefix and postfix flavor. To tell one from the other, the postfix variants take an additional dummy int argument. If you overload increment or decrement, be sure to always implement both prefix and postfix versions. Here is the canonical implementation of increment, decrement follows the same rules:

class X {
  X& operator++()
  {
    // do actual increment
    return *this;
  }
  X operator++(int)
  {
    X tmp(*this);
    operator++();
    return tmp;
  }
};

Note that the postfix variant is implemented in terms of prefix. Also note that postfix does an extra copy.2

Overloading unary minus and plus is not very common and probably best avoided. If needed, they should probably be overloaded as member functions.

2 Also note that the postfix variant does more work and is therefore less efficient to use than the prefix variant. This is a good reason to generally prefer prefix increment over postfix increment. While compilers can usually optimize away the additional work of postfix increment for built-in types, they might not be able to do the same for user-defined types (which could be something as innocently looking as a list iterator). Once you got used to do i++, it becomes very hard to remember to do ++i instead when i is not of a built-in type (plus you'd have to change code when changing a type), so it is better to make a habit of always using prefix increment, unless postfix is explicitly needed.

Binary arithmetic operators

For the binary arithmetic operators, do not forget to obey the third basic rule operator overloading: If you provide +, also provide +=, if you provide -, do not omit -=, etc. Andrew Koenig is said to have been the first to observe that the compound assignment operators can be used as a base for their non-compound counterparts. That is, operator + is implemented in terms of +=, - is implemented in terms of -= etc.

According to our rules of thumb, + and its companions should be non-members, while their compound assignment counterparts (+= etc.), changing their left argument, should be a member. Here is the exemplary code for += and +; the other binary arithmetic operators should be implemented in the same way:

class X {
  X& operator+=(const X& rhs)
  {
    // actual addition of rhs to *this
    return *this;
  }
};
inline X operator+(X lhs, const X& rhs)
{
  lhs += rhs;
  return lhs;
}

operator+= returns its result per reference, while operator+ returns a copy of its result. Of course, returning a reference is usually more efficient than returning a copy, but in the case of operator+, there is no way around the copying. When you write a + b, you expect the result to be a new value, which is why operator+ has to return a new value.3 Also note that operator+ takes its left operand by copy rather than by const reference. The reason for this is the same as the reason giving for operator= taking its argument per copy.

The bit manipulation operators ~ & | ^ << >> should be implemented in the same way as the arithmetic operators. However, (except for overloading << and >> for output and input) there are very few reasonable use cases for overloading these.

3 Again, the lesson to be taken from this is that a += b is, in general, more efficient than a + b and should be preferred if possible.

Array Subscripting

The array subscript operator is a binary operator which must be implemented as a class member. It is used for container-like types that allow access to their data elements by a key. The canonical form of providing these is this:

class X {
        value_type& operator[](index_type idx);
  const value_type& operator[](index_type idx) const;
  // ...
};

Unless you do not want users of your class to be able to change data elements returned by operator[] (in which case you can omit the non-const variant), you should always provide both variants of the operator.

If value_type is known to refer to a built-in type, the const variant of the operator should better return a copy instead of a const reference:

class X {
  value_type& operator[](index_type idx);
  value_type  operator[](index_type idx) const;
  // ...
};

Operators for Pointer-like Types

For defining your own iterators or smart pointers, you have to overload the unary prefix dereference operator * and the binary infix pointer member access operator ->:

class my_ptr {
        value_type& operator*();
  const value_type& operator*() const;
        value_type* operator->();
  const value_type* operator->() const;
};

Note that these, too, will almost always need both a const and a non-const version. For the -> operator, if value_type is of class (or struct or union) type, another operator->() is called recursively, until an operator->() returns a value of non-class type.

The unary address-of operator should never be overloaded.

For operator->*() see this question. It's rarely used and thus rarely ever overloaded. In fact, even iterators do not overload it.


Continue to Conversion Operators

sbi
  • 204,536
  • 44
  • 236
  • 426
  • 92
    `operator->()` is actually *extremely* weird. It's not required to return a `value_type*` -- in fact, it can return another class type, **provided that class type has an `operator->()`**, which will then be called subsequently. This recursive calling of `operator->()`s proceeds until a `value_type*` return type occurs. Madness! :) – j_random_hacker Feb 22 '11 at 11:20
  • @j_random_hacker: I'm just trying to not to put too much information into these "basic rules". This answer is already very long. So I've upvoted your comment instead to make it visible above the rest of the commentary noise. However, feel free to add your information to the answer if you think it warrants being mentioned in the answer proper. – sbi Feb 22 '11 at 13:30
  • 2
    Note that there are cases when defining `operatorX` in terms of `operatorX=` if not practical. For matrices and polynomials (english?), code factorization of the multiplication goes the other way: `operator*=` should be defined in terms of `operator*`. – Luc Hermitte Oct 11 '12 at 13:03
  • @LucHermitte: I have yet to encounter a case where doing it the other way would be more effective, but I do not doubt that they exist. This is all rules of thumb, after all. – sbi Oct 11 '12 at 13:14
  • 3
    It's not exactly about effectiveness. It's about we cannot do it in the traditional-idiomatic way in a (very) few cases: when the definition of both operands need to stay unchanged while we compute the result. And as I said, there are two classical examples: matrices multiplication, and multiplication of polynomials. We could define `*` in terms of `*=` but it would be awkward because one of the first operation of `*=` would to create a new object, result of the computation. Then, after the for-ijk loop, we would swap this temporary object with `*this`. ie. 1.copy, 2.operator*, 3.swap – Luc Hermitte Oct 11 '12 at 14:02
  • Defining operatorX in terms of operatorX= prevents the former from being `constexpr`, making it another case of switching which one derives from the other. – CTMacUser Jan 06 '13 at 10:46
  • 6
    I disagree with the const/non-const versions of your pointer-like operators, e.g. ` const value_type& operator*() const;` - this would be like having a `T* const` returning a `const T&` on dereferencing, which is not the case. Or in other words: a const pointer does not imply a const pointee. In fact, it is not trivial to mimic `T const *` - which is the reason for the whole `const_iterator` stuff in the standard library. Conclusion: the signature should be `reference_type operator*() const; pointer_type operator->() const` – Arne Mertz Apr 09 '13 at 14:02
  • 6
    One comment: The implementation of binary arithmetic operators suggested is not such efficient as it can be. Se Boost operators headers simmetry note: http://www.boost.org/doc/libs/1_54_0/libs/utility/operators.htm#symmetry One more copy can be avoided if you use a local copy of the first parameter, do +=, and return the local copy. This enables NRVO optimization. – Manu343726 Jul 19 '13 at 08:36
  • 3
    As I mentioned in the chat, `L <= R` can also be expressed as `!(R < L)` instead of `!(L > R)`. Might save an extra layer of inlining in hard-to-optimize expressions (and it's also how Boost.Operators implements it). – TemplateRex Oct 10 '13 at 18:24
  • Trying when the rule of thumb doesn't apply. The `==` operator treat both objects as equal, but surely it often would need to access private members to compare - will that work when it's a non-member? – thomthom Dec 03 '13 at 23:47
  • 2
    @thomthom: If a class doesn't have a publicly accessible API for getting at its state, you will have to either make everything that needs to access its state a member or a `friend` of the class. This, of course, is also true for all operators. – sbi Dec 04 '13 at 08:12
  • 1
    @jbi http://juanchopanzacpp.wordpress.com/2014/05/11/want-speed-dont-always-pass-by-value/ – Pharap Jul 19 '14 at 10:59
  • I tried implementing `operator|` as per your suggestion to follow arithmetic rules but this doesn't compile because I have the wrong number of arguments `inline X operator|(X lhs, const X &rhs)` ? – Jon Cage May 03 '17 at 16:25
  • @Jon: That would be the free function implementation. You didn't put this into a class, did you? Read [here](http://stackoverflow.com/a/4421715/140719): _"A binary infix operator `@`, applied to the objects `x` and `y`, is called either as `operator@(x,y)` or as `x.operator@(y)`."_ – sbi May 07 '17 at 20:44
  • 3
    The section on comparison operators will need an update to mention `operator<=>()` when that's final (C++20). – Toby Speight Jul 11 '18 at 11:08
  • @Toby Indeed. Thanks for pointing this out. However, this guide's goal is to present experience and common wisdom collected over the years, and any text about `operator<=>`, because of it being brand new, will not be up to that standard. But I guess that can't be helped. – sbi Jul 12 '18 at 06:11
  • In your case, @JonCage, arithmetic operators such as `operator|()` should be defined outside the class definition, or specified as `friend` functions if defined inside the class definition. If defined inside the class definition, but not specified as `friend`s, they'll be member functions (which isn't what you want). – Justin Time - Reinstate Monica Oct 10 '19 at 18:44
  • For bitwise operators, the first use cases that come to mind are when creating a bit-field enum, or making a wrapper for a bit field. – Justin Time - Reinstate Monica Oct 10 '19 at 18:49
  • Can someone explain "If value_type is known to refer to a built-in type, the const variant of the operator should better return a copy instead of a const reference" – anonuser01 Apr 27 '20 at 13:41
  • @Iamanon: Passing a built-in by reference is not more efficient than passing it by copy, so there's nothing to be gained by returning by reference, – sbi Jul 11 '20 at 20:55
521

The Three Basic Rules of Operator Overloading in C++

When it comes to operator overloading in C++, there are three basic rules you should follow. As with all such rules, there are indeed exceptions. Sometimes people have deviated from them and the outcome was not bad code, but such positive deviations are few and far between. At the very least, 99 out of 100 such deviations I have seen were unjustified. However, it might just as well have been 999 out of 1000. So you’d better stick to the following rules.

  1. Whenever the meaning of an operator is not obviously clear and undisputed, it should not be overloaded. Instead, provide a function with a well-chosen name.
    Basically, the first and foremost rule for overloading operators, at its very heart, says: Don’t do it. That might seem strange, because there is a lot to be known about operator overloading and so a lot of articles, book chapters, and other texts deal with all this. But despite this seemingly obvious evidence, there are only a surprisingly few cases where operator overloading is appropriate. The reason is that actually it is hard to understand the semantics behind the application of an operator unless the use of the operator in the application domain is well known and undisputed. Contrary to popular belief, this is hardly ever the case.

  2. Always stick to the operator’s well-known semantics.
    C++ poses no limitations on the semantics of overloaded operators. Your compiler will happily accept code that implements the binary + operator to subtract from its right operand. However, the users of such an operator would never suspect the expression a + b to subtract a from b. Of course, this supposes that the semantics of the operator in the application domain is undisputed.

  3. Always provide all out of a set of related operations.
    Operators are related to each other and to other operations. If your type supports a + b, users will expect to be able to call a += b, too. If it supports prefix increment ++a, they will expect a++ to work as well. If they can check whether a < b, they will most certainly expect to also to be able to check whether a > b. If they can copy-construct your type, they expect assignment to work as well.


Continue to The Decision between Member and Non-member.

Community
  • 1
  • 1
sbi
  • 204,536
  • 44
  • 236
  • 426
  • 16
    The only thing of which I am aware which violates any of these is `boost::spirit` lol. – Billy ONeal Dec 12 '10 at 17:50
  • 71
    @Billy: According to some, abusing `+` for string concatenation is a violation, but it has by now become well established praxis, so that it seems natural. Although I do remember a home-brew string class I saw in the 90ies that used binary `&` for this purpose (referring to BASIC for established praxis). But, yeah, putting it into the std lib basically set this in stone. The same goes for abusing `<>` for IO, BTW. Why would left-shifting be the obvious output operation? Because we all learned about it when we saw our first "Hello, world!" application. And for no other reason. – sbi Dec 12 '10 at 19:56
  • 1
    "_the meaning of an operator is not obviously clear and undisputed_" and how do you determine that? – curiousguy Dec 01 '11 at 12:18
  • 5
    @curiousguy: If you have to explain it, it's not obviously clear and undisputed. Likewise if you need to discuss or defend the overloading. – sbi Dec 02 '11 at 12:09
  • So overloading == for containers is an abuse? – curiousguy Dec 02 '11 at 12:11
  • 2
    This *seems* good sense, but has drawbacks: Point 1 will make boost::spirit impossible to exist, and the same can apply to iostream (does cout << "hello world" shift bits?) Point2 literally inhibits whatever innovation: something just invented isn't "well known", but me become as such in future. std::string use + not to "add". And they where not "well known" before STL had been invented. – Emilio Garavaglia Apr 09 '12 at 07:58
  • 1
    @Emilio: These rules are for the common C++ developer. Of course they would prohibit creating anything like IO streams or spirit or, as I said above, even a decent string class. Read again, I preceded this with "Sometimes people have deviated from them and the outcome was not bad code, but such positive deviations are few and far between." IOW: When you are a beginner, strictly stick to those rules. When you are an experienced C++ developer (that's after several years), you might form your own opinion. When you deviate as far as, say, spirit does, rely on peer reviews to judge your ideas. – sbi Apr 09 '12 at 10:16
  • 1
    @curiousguy: Why? What could it do but compare containers, element by element, for equality? Isn't that obvious? – sbi Apr 09 '12 at 10:16
  • 5
    @sbi: "peer review" is always a good idea. To me a badly choosen operator is not different from a badly choosen function name (I saw many). Operator are just functions. No more no less. Rules are just the same. And to understand if an idea is good, the best way is understand how long does it takes to be understood. (Hence, peer review is a must, but peers must be chosen between people free from dogmas and prejudice.) – Emilio Garavaglia Apr 09 '12 at 16:57
  • @Emilio: I have no idea what this is arguing for or against. Are you sure you were replying to _my_ comment? – sbi Apr 09 '12 at 18:02
  • @sbi "_Isn't that obvious?_" It isn't obvious to me that two containers should compare equal even if they aren't equivalents. – curiousguy Apr 09 '12 at 20:15
  • 2
    @curiousguy: That's the Java/C# approach. In C++, containers hold _values_, rather than _references_, so the difference between "equality" and "equivalence" is moot. (If I got the difference right, that is.) – sbi Apr 09 '12 at 20:42
  • 5
    @sbi To me, the only absolutely obvious and indisputable fact about `operator==` is that it should be an equivalence relation (IOW, you should not use non signaling NaN). There are many useful equivalence relations on containers. What does equality means? "`a` equals `b`" means that `a` and `b` have the same mathematical value. The concept of mathematical value of a (non-NaN) `float` is clear, but the mathematical value of a container can have many distinct (type recursive) useful definitions. The strongest definition of equality is "they are the same objects", and it is useless. – curiousguy Apr 10 '12 at 00:49
  • 1
    (...) The second strongest definition is "holds the same objects", and it is useless for value containers. Another strong definition is "two objects are equal iff they cannot be distinguished using their public interface" (comparison of addresses isn't "part of the public interface"). This relates to simulation and bi-simulation. The nuances with this definition comes with the parts of the interface you are allowed to use. – curiousguy Apr 10 '12 at 00:55
  • 1
    (...) Are the two `set>` ({1},) equal? They have the same elements, but 1) if you can "compare" their comparator, you will be able to distinguish them; 2) if you add another element 2, their elements as a sequence won't be the same. Are two `hash_set` with the same elements in a different order equal? Neither of these questions are absolutely obvious (at least to me). – curiousguy Apr 10 '12 at 00:59
  • 1
    (...) Also, what should `operator= (x)` do? Should it be equivalent with copy construction? Should it be equivalent with `assign(x.begin(),x.end())`? Both are very reasonable choices. I feel that there are strong arguments for both. This seems to argue against providing this operator at all. – curiousguy Apr 10 '12 at 01:08
  • 2
    @sbi: It's conceptually against, but recognizes a good point. Essentially I don't believe in a difference between operators and functions: if + for "concatenation" or unary* for "keen star" or ~for "orthogonal" or "transposed" can be questionable, std::string::empty is also questionable (an imperative verb used to check a state ?!? Wouldn't it be is_empty better?). (...) – Emilio Garavaglia Apr 10 '12 at 06:18
  • 1
    (...) In any case, wherever you define a symbolic name, you define a convention between that name and what it represent. This convention cannot be obvious to anyone but you, until you don't expose enough "information" (in "information theory" sense) to your users (may be a comment, a document or a trivial use case, or the raw source code- when very simple). But I must see a clean contradiction (and may be even a "clutural racism" -note the quotes- in the background: saying "When you are a beginner, strictly stick to those rules", will defeat any geniality to emerge. (...) – Emilio Garavaglia Apr 10 '12 at 06:22
  • 2
    (...) The real fact is that, when you are a beginner the first sample of overloading yopu see is `cout << "hello world"`, that is just a violation to the rules (`< – Emilio Garavaglia Apr 10 '12 at 06:22
  • 1
    (...) The "insertion operator" is for stream and the shift operator for integers. The both have incidentally the same aspect. For this reason I always teach about `< – Emilio Garavaglia Apr 10 '12 at 06:30
  • 2
    @curiousguy: No, you are making this way to complicated. The obvious implementation for `operator==()` on a heterogeneous container (aka `struct`) is that, for all of its elements (aka "members"), `operator==()` returns true when applied to the corresponding element in another `struct` of the same type. The obvious meaning for `operator==()` of a non-heterogeneous container is that, for all elements in the container, `operator==()` returns true when applied to the corresponding object in another container of the same type. – sbi Apr 10 '12 at 07:14
  • @Emilio: I have allowed for violations of the rules, and I have listed IO streams and strings (and spirit) as obvious examples of those violations being successful. But that doesn't mean that a C++ newbie thinking overloading `!` for strings might be a neat idea has it right. IO streams were designed ~30 years ago, when operator overloading was the newest thing in C++, brings a lot of historical weight, and, as you pointed out, newbies will usually learn the meaning of `< – sbi Apr 10 '12 at 07:28
  • @Emilio: `std::string`, despite all its shortcomings, unified the C++ world which was split into thousands of different string classes. That alone was a great deed, and the designers would have been hard-pressed to do anything else so wrong for it to not be seen as a success — despite the fact that some disagreed with its (ab)use of `+` for concatenation. – sbi Apr 10 '12 at 07:31
  • 1
    @Emilio: And spirit deliberately set out to abuse operator overloading in order to create an embedded domain-specific language. That's not necessarily the first thing a newbie does, it might well be one of the most often legitimate reasons to abuse a programming language, and a very hard task to succeed with unless you have the backup of a strong community. – sbi Apr 10 '12 at 07:32
  • 2
    @sbi: Your all arguments reduce to "don't do unless somebody else already did it a number of times". Apply this to "make children" and to "anyone", and humanity will extinguish in one generation time! It's a hard dirty work, but someone has to begin. Newbie or experts, is not the point. The *idea* is the point. If there is enough "believers" the idea goes, otherwise will die. Don't be "racist" against newbies: instead to tell them to "go away from water", teach them "how to swim"! (You may be surprised!) – Emilio Garavaglia Apr 10 '12 at 07:45
  • 2
    @Emilio: Yes, my suggestion to those seeking advice is to not to invent something new. In the last 20 years, I have seen a lot of abuse of operator overloading, and very little justified use. (And I have been guilty of this, too, in my first few years of C++.) Consequently, my advice is to stick to well-known paradigms, unless you know enough of operator overloading that you wouldn't need advice in the first place. (As for the rest of your argument: The comparisons fall so awkwardly short, I won't spend time on them.) – sbi Apr 10 '12 at 07:55
  • 1
    Please take extended discussions to [chat], in particular [this room](http://chat.stackoverflow.com/rooms/10/loungec) – Tim Post Apr 10 '12 at 07:57
  • @sbi So, are you trying to say that `operator==` for containers is ill-specified, or are you just saying it without actually trying to say that? – curiousguy Apr 10 '12 at 08:39
  • @sbi "_In the last 20 years, I have seen a lot of abuse of operator overloading, and very little justified use._" What kind of abuses have you seen? Mostly subtle abuses, or ridiculous abuses? – curiousguy Apr 10 '12 at 08:43
  • @BenVoigt after `x = y;` the value/state of `x` is equal to/equivalent with the value/state of `y` before, so it is not totally crazy. Also, the C++ language allows both `C(const C&)` and `C(C&)` as copy-ctor signatures, and `operator=(const C&)` as well as `operator=(C&)` for assignment operator signature, so the core language quite explicitly supported this design too. – curiousguy Jun 27 '12 at 22:18
  • 3
    @curiousguy: The language allows defining `operator+` as subtraction also. It's a very VERY bad idea, because it's surprising. `x = y;` should not change `y`. It does not do so for any built-in type. Support for `C::operator=(C&)` is needed to support things like reference-counted pointers, where internal state may change but the user-visible state does. `std::auto_ptr` is universally recognized as a mistake. – Ben Voigt Jun 27 '12 at 22:40
  • @BenVoigt "_The language allows defining operator+ as subtraction also._" actually the code language doesn't know addition from subtraction, so it couldn't tell. OTOH, the core language knows quite well what a copy ctor means. "_Support for C::operator=(C&) is needed to support things like reference-counted pointers, where internal state may change but the user-visible state does._" No it is not. – curiousguy Jun 27 '12 at 23:07
  • 1
    Yeah, I agree that cout << "Hello world" is the worst violation of these rules. I'm convinced that it was implemented as a demonstration of what operator overloading could do, and we never intended to become used in the real world. – Edward Falk Apr 12 '13 at 17:17
  • Why did you write that Comparison operators should be implemented as non-member functions? What is the reason? – Sekory Feb 24 '15 at 19:42
  • @Sekory: Did I even write this in this answer? Anyway, it's explained [here](http://stackoverflow.com/questions/4421706/operator-overloading-in-c/4421729#4421729): _If a binary operator treats_ ___both operands equally___ _(it leaves them unchanged), implement this operator as a_ ___non-member___ _function._ What exactly do you want to know. – sbi Feb 26 '15 at 08:39
  • With respect to "whenever the meaning of an operator is not obviously clear and undisputed, it should not be overloaded", would overloading < and > for a vector class comparing length violate this principle? – Robinson Jun 08 '15 at 10:52
  • 2
    @Robinson: The STL defines comparison of containers as lexicographical comparison, not as length. Therefore, everybody looking at `v1 < v2` would expect it to do so, too. For what you want, there's `v1.size() < v2.size()`. – sbi Jun 08 '15 at 11:54
  • The assignment operator is overloaded by default, right? – Moiz Sajid Aug 30 '15 at 11:30
  • 2
    @Moiz: In case you want to know whether the compiler generates an assignment operator by default, see [this question](http://stackoverflow.com/q/3734247/140719) and its answer. – sbi Aug 30 '15 at 13:24
  • 1
    Tying into these rules, I would personally say that the best reason to overload an operator is to provide consistency with similar classes. If you're making a math-related class, for instance, it would be reasonable to overload assignment, arithmetic, and comparison operators for use with said class, conversion operators to convert to built-in and/or standard math types, and I/O operators; not so much array, new/delete, or pointer-like operators. Conversely, if you're making a video game character class, it's unreasonable to overload arithmetic operators to modify the character's level. – Justin Time - Reinstate Monica Feb 02 '16 at 19:58
  • How would you feel about `operator|` for piping, such as in [range adaptors](http://www.boost.org/doc/libs/1_62_0/libs/range/doc/html/range/reference/adaptors/introduction.html)? – Daniel H Jun 27 '17 at 21:02
  • 4
    @Daniel: Look, if nobody had come up with overloading `<>` for IO, and you came up with it now, it would be frowned upon. Since it's been done 30 years ago, it's part of the domain now. The same goes for everything else that's not in common use: If you or I do it in our projects, it's rather likely our co-workers will complain. If it is done in a popular boost library, and fits the domain of the code (using `|` for piping is well-known), this might be different. – sbi Jul 05 '17 at 15:37
  • The real world is not that ideal. For example, the `operator+` should be Abelian (i.e. commutative) to serve to the well-formed semantics, but almost every design of string concatenation by operator overloading break this rule. – FrankHB Feb 06 '21 at 08:31
  • @FrankHB See this comment upthread: https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading/4421708?noredirect=1#comment4827006_4421708 – sbi Mar 30 '21 at 20:33
273

The General Syntax of operator overloading in C++

You cannot change the meaning of operators for built-in types in C++, operators can only be overloaded for user-defined types1. That is, at least one of the operands has to be of a user-defined type. As with other overloaded functions, operators can be overloaded for a certain set of parameters only once.

Not all operators can be overloaded in C++. Among the operators that cannot be overloaded are: . :: sizeof typeid .* and the only ternary operator in C++, ?:

Among the operators that can be overloaded in C++ are these:

  • arithmetic operators: + - * / % and += -= *= /= %= (all binary infix); + - (unary prefix); ++ -- (unary prefix and postfix)
  • bit manipulation: & | ^ << >> and &= |= ^= <<= >>= (all binary infix); ~ (unary prefix)
  • boolean algebra: == != < > <= >= || && (all binary infix); ! (unary prefix)
  • memory management: new new[] delete delete[]
  • implicit conversion operators
  • miscellany: = [] -> ->* , (all binary infix); * & (all unary prefix) () (function call, n-ary infix)

However, the fact that you can overload all of these does not mean you should do so. See the basic rules of operator overloading.

In C++, operators are overloaded in the form of functions with special names. As with other functions, overloaded operators can generally be implemented either as a member function of their left operand's type or as non-member functions. Whether you are free to choose or bound to use either one depends on several criteria.2 A unary operator @3, applied to an object x, is invoked either as operator@(x) or as x.operator@(). A binary infix operator @, applied to the objects x and y, is called either as operator@(x,y) or as x.operator@(y).4

Operators that are implemented as non-member functions are sometimes friend of their operand’s type.

1 The term “user-defined” might be slightly misleading. C++ makes the distinction between built-in types and user-defined types. To the former belong for example int, char, and double; to the latter belong all struct, class, union, and enum types, including those from the standard library, even though they are not, as such, defined by users.

2 This is covered in a later part of this FAQ.

3 The @ is not a valid operator in C++ which is why I use it as a placeholder.

4 The only ternary operator in C++ cannot be overloaded and the only n-ary operator must always be implemented as a member function.


Continue to The Three Basic Rules of Operator Overloading in C++.

Community
  • 1
  • 1
sbi
  • 204,536
  • 44
  • 236
  • 426
  • `~` is unary prefix, not binary infix. – mrkj Nov 02 '12 at 05:15
  • 1
    `.*` is missing from the list of non-overloadable operators. – celticminstrel Jul 04 '15 at 05:35
  • @celticminstrel: Indeed, and nobody noticed for 4.5 years... Thanks for pointing it out, I put it in. – sbi Jul 04 '15 at 19:56
  • _non-overloadable_! So, up there with `.` and `::`. And, it's probably because most people never use pointers-to-members. – celticminstrel Jul 04 '15 at 21:11
  • @celticminstrel: I was reading/writing `.*`, but _thinking_ `->*`, and therefore overlooking your _non_-overloadable. Anyway, the list of non-overloadable operators is not meant to be exhaustive (_"Among the operators that cannot be overloaded..."_), but since `->*` was missing, I'll edit it in. – sbi Jul 04 '15 at 22:24
  • Isn't it a bit confusing to use `@` instead of a real example of a unary/binary operator? Some may mistakenly assume `@` is actually an operator that is overloadable. (EDIT: I realize you've pointed this out in the postscript, but no one reads the postscript.) – Mateen Ulhaq Sep 09 '15 at 01:03
  • 2
    @Mateen I _wanted_ to use a placeholder instead of a real operator in order to make clear that this isn't about a special operator, but applies to all of them. And, if you want to be a C++ programmer, you should learn to pay attention even to the smallprint. `:)` – sbi Sep 11 '15 at 10:57
  • ->* is listed both as an operator that cannot be overloaded, and, under miscellany, as one that can be. – Rory Yorke Dec 12 '15 at 11:04
  • @Rory: It seems bruziuz did this in his edit a few days ago, and I missed it. Thanks for pointing it out! I fixed it. – sbi Dec 12 '15 at 19:56
  • I am a beginner and I use code:blocks. When I use `operator+(x,y)` for overloading the plus operator I get an error that the operator can only take one argument! :( – Hosein Rahnama Jul 13 '18 at 14:47
  • 1
    @H.R.: Had you read this guide, you would know what's wrong. I generally suggest that you should read the the first three answers linked from the question. That shouldn't be more than half an hour of your life, and gives you a basic understanding. The operator-specific syntax you can look up later. Your specific problem suggests you try to overload `operator+()` as a member function, but gave it the signature of a free function. See [here](https://stackoverflow.com/a/4421729/140719). – sbi Jul 13 '18 at 23:11
  • 1
    @sbi: I have read the three first post already and thank you for making them. :) I will try resolve the problem otherwise I think that it is better to ask it on a separate question. Thank you again for making life so easy for us! :D – Hosein Rahnama Jul 14 '18 at 02:00
  • Addendum: Some compilers provide a (typically hidden, internal) switch that allows you to overload operators for non-user-defined types. Any code that redefines built-in operators in this manner is non-compliant. – Justin Time - Reinstate Monica Aug 15 '19 at 21:10
264

The Decision between Member and Non-member

The binary operators = (assignment), [] (array subscription), -> (member access), as well as the n-ary () (function call) operator, must always be implemented as member functions, because the syntax of the language requires them to.

Other operators can be implemented either as members or as non-members. Some of them, however, usually have to be implemented as non-member functions, because their left operand cannot be modified by you. The most prominent of these are the input and output operators << and >>, whose left operands are stream classes from the standard library which you cannot change.

For all operators where you have to choose to either implement them as a member function or a non-member function, use the following rules of thumb to decide:

  1. If it is a unary operator, implement it as a member function.
  2. If a binary operator treats both operands equally (it leaves them unchanged), implement this operator as a non-member function.
  3. If a binary operator does not treat both of its operands equally (usually it will change its left operand), it might be useful to make it a member function of its left operand’s type, if it has to access the operand's private parts.

Of course, as with all rules of thumb, there are exceptions. If you have a type

enum Month {Jan, Feb, ..., Nov, Dec}

and you want to overload the increment and decrement operators for it, you cannot do this as a member functions, since in C++, enum types cannot have member functions. So you have to overload it as a free function. And operator<() for a class template nested within a class template is much easier to write and read when done as a member function inline in the class definition. But these are indeed rare exceptions.

(However, if you make an exception, do not forget the issue of const-ness for the operand that, for member functions, becomes the implicit this argument. If the operator as a non-member function would take its left-most argument as a const reference, the same operator as a member function needs to have a const at the end to make *this a const reference.)


Continue to Common operators to overload.

Community
  • 1
  • 1
sbi
  • 204,536
  • 44
  • 236
  • 426
  • 10
    Herb Sutter's item in Effective C++ (or is it C++ Coding Standards?) says one should prefer non-member non-friend functions to member functions, to increase the encapsulation of the class. IMHO, the encapsulation reason takes precedence to your rule of thumb, but it does not decrease the quality value of your rule of thumb. – paercebal Dec 12 '10 at 13:36
  • 10
    @paercebal: _Effective C++_ is by Meyers, _C++ Coding Standards_ by Sutter. Which one are you referring to? Anyway, I dislike the idea of, say, `operator+=()` not being a member. It has to change its left-hand operand, so by definition it has to dig deep into its innards. What would you gain by not making it a member? – sbi Dec 12 '10 at 13:39
  • @paercebal You are referring to *Effective C++* by Meyers, not Sutter. – Karl von Moor Dec 12 '10 at 13:49
  • @Polybos: Which item is that in _EC++_? – sbi Dec 12 '10 at 13:56
  • 10
    @sbi: Item 44 in C++ Coding Standards (Sutter) **Prefer writing nonmember nonfriend functions**, of course, it only applies if you can actually write this function using only the public interface of the class. If you cannot (or can but it would hinder performance badly), then you have to make it either member or friend. – Matthieu M. Dec 12 '10 at 15:45
  • 4
    @sbi : Oops, Effective, Exceptional... No wonder I mix the names up. Anyway the gain is to limit as much as possible the number of functions that have access to an object private/protected data. This way, you increase the encapsulation of your class, making its maintenance/testing/evolution easier. – paercebal Dec 12 '10 at 16:51
  • 13
    @sbi : One example. Let's say you're coding a String class, with both the `operator +=` and the `append` methods. The `append` method is more complete, because you can append a substring of the parameter from index i to index n -1: `append(string, start, end)` It seems logical to have `+=` call append with `start = 0` and `end = string.size`. At that moment, append could be a member method, but `operator +=` doesn't need to be a member, and making it a non-member would decrease the quantity of code playing with the String innards, so it is a good thing.... ^_^ ... – paercebal Dec 12 '10 at 16:58
  • 1
    @paercebal: (Did you know there's also _Efficient C++_?) I see. If you had an `append()` method to your string class, `+=` could indeed be a non-member. But, for one, using `+` and `+=` for strings is questionable at best (isn't `+` supposed to b be commutative?) and only alright because it's based on existing praxis. Also, even though I do agree with Sutter on this (BTW, I think it was Meyers who first published an article on non-members actually _improving_ encapsulation, hence my confusion) I might _still_ make `+=` a member for the very same reason: existing praxis. – sbi Dec 12 '10 at 17:24
  • @sbi : I did know about both Sutter and Meyers books: I own almost all of them. – paercebal Dec 12 '10 at 17:47
  • 2
    @sbi : Commutativity should not be a criterion. For example, Matrices multiplication is not commutative, while number multiplication is. Should I be forbidden to overload `*` for matrices just because the C++ native integer `*` is commutative? No. Here, the principle of least surprise apply, and we must analyze an operator according to its context (i.e. its parameters). The same goes for strings and operator `+` (and by extension, `+=`). The fact is, no one expects the `+` operator to be commutative on strings, so, where's the problem with that? – paercebal Dec 12 '10 at 17:56
  • 2
    @sbi : Now, the existing practice about an operator could apply to an interface (e.g. provide `+` and `+=` operators on strings because users do expect them), it should not be used to decide the implementation detail IMHO (e.g. decide `+=` is to be member or non-member). This implementation detail is not about personal preference of taste: Decreasing the quantity of code accessing private data (i.e. encapsulation) is a good thing, and can be measured, so it should be pursued as much as possible (as long as the code remains clear, readable and correct, of course) – paercebal Dec 12 '10 at 18:00
  • 1
    It's definitely better to implement either `+` or `+=` outside the class (and likewise for the other operators `@` that come with a `@=` version) for the reason paercebal gave. Here's an idea: since `+=` is usually more efficient, implement `+=` inside the class, and then have a *templated* `operator+()` that is enabled using `enable_if` only for classes `T` for which `want_helper_ops` is defined. Nuke that boilerplate! :) – j_random_hacker Dec 12 '10 at 18:05
  • @paercebal: Yes, using `<>` for IO and `+` for string concatenation is established praxis. And I'm not opposed to any of them. What I'm saying is that there are arguments against doing so, and that, until it is established praxis, according my Three Basic Rules, to it shouldn't be done. (Yes I know it can't become established praxis unless you violate rule #1.) As for making `+=` a non-member: Yes, it seems logical, but it never occurred to me, because I overload operators by those three rules for more than a decade. And such long-nursed habits die hard. – sbi Dec 12 '10 at 20:00
  • @j_random_hacker: The question is not whether _one_ of them should be non-member, I think that's unanimously clear. The question is whether both of them should. See me previous comment to paercebal regarding this. – sbi Dec 12 '10 at 20:01
  • 1
    This rule sounds weird: `If a binary operator does not treat both of its operands equally (usually it will change its left operand), it should be a member function of its left operand’s type.`. The motivation for making it a member is not that both operands aren't treated equal. I think you should reword that item. An `operator/` that does numeric division will treat the left operand different from the right. Still it should be written as a non-member. – Johannes Schaub - litb Dec 13 '10 at 04:46
  • 1
    @sbi : "And such long-nursed habits die hard." : I know... I'm trying to get rid of my hungarian notation habit... :-( – paercebal Dec 13 '10 at 09:38
  • @Johannes: If an operator changes its left-hand operand, it needs access to its innards. – sbi Dec 13 '10 at 15:04
  • 1
    @sbi : "If an operator changes its left-hand operand, it needs access to its innards". No: The operator could use a method, so it doesn't need to have access to protected/private member. Again, in my example for strings, `operator +=` doesn't need to access private members. It only needs only call the public `append` method with the right parameters. – paercebal Dec 14 '10 at 10:38
  • @paercebal: I changed the wording somewhat. Do you approve of this now or does it need further changes? – sbi Dec 14 '10 at 10:54
  • 1
    @sbi : After thinking about it, the list should be something like: 1. "if possible, make it non-member non-friend", 2. "The following operators are available only as member-functions: ...". . . Everything else seems a matter of taste. My own viewpoint on the subject is similar to yours, but it is still a matter of taste, and this excellent question/answers set should not be tainted by personal tastes. It should be *the reference*, motivated only by rock hard reasons. – paercebal Dec 14 '10 at 21:38
  • 1
    @paercebal: But I consider "if possible..." too vague for a rule of thumb. And that's what I'm trying to hand out here: an easy-to-remember rule of thumb, which you can remember even if you can't remember all the reasoning. As it now is, my rule is basically saying "make it a non-member, if it's changing the left operand, consider membership". If most of you out there don't think this is enough, I will change t. But "if possible..." isn't enough to improve what I now have. – sbi Dec 14 '10 at 22:13
  • @sbi : For me, the "if possible..." means "if it compiles...". Some operators *must* be member functions. For the others, I guess non-member functions should be preferred anyway, *even if `friend`*, because these authorizes a cast from some value into the class value (e.g. having the code `MyInteger m(42), n ; n = 25 + m ;` work). – paercebal Dec 15 '10 at 11:00
  • @sbi : With your authorization, I could think about an alternate list of items, and write it as a "proposition" at the end of the post (the comments are not suited for this lengthy discussion). Another possibility would be to contact me by email (append "@" + "gmail" + "." + "com" to my identifier) – paercebal Dec 15 '10 at 11:00
  • @paercebal: If it's too long for comments, why don't we discuss this in the [C++ chat](http://chat.stackoverflow.com/rooms/10/c-lounge)? That's where the whole [FAQ idea](http://meta.stackexchange.com/questions/68647/setting-up-a-faq-for-the-c-tag) started out. It's pretty quiet there now (and I can't do online discussions now either), but in about 5-10hrs it usually looks very different. (If you want, you can post your ideas there now anyway, they won't get lost.) – sbi Dec 15 '10 at 11:56
  • 1
    @sbi I only just saw this thread and I hope this question will be answered though this thread is nearly 2 years old now. With respect to overloading the binary operators, why should the operator not be a member function if it treats both operands equally (or doesn't change their innards)? – Andrew Falanga Sep 26 '12 at 16:34
  • @AndrewFalanga this comment answers your question: http://stackoverflow.com/questions/4421706/operator-overloading/4421729#comment4825732_4421729 – Dennis Aug 17 '13 at 07:30
  • Is there a recommended place for helper (non-member) functions? In the same file as the class, or in a separate file but in the same namespace as the class? – Dennis Aug 17 '13 at 07:32
  • 1
    @Dennis: If they are part of the class' interface (like `widget operator+(const widget&, const widget&)` or `void normalize(widget&)`, they should be in the class' namespace and close to the class' declaration. If they are merely private helpers, hide them in (the unnamed namespace of) the `.cpp` file or, should everything be in headers, in some `namespace details`. – sbi Aug 17 '13 at 10:41
  • I may be wrong, but I feel that the case of the unary minus operator is forgotten (-a)… The rules of thumb states that “If it is a unary operator, implement it as a member function.”, but unary minus operator is a unary operator, yet it would be more logical to implement this operator as a non-member function (because after all, it leaves the operand unchanged). By the way, the same holds for unary plus operator. – mlpo Dec 21 '14 at 16:59
  • @mlpo: As far as I can see I hadn't even mentioned unary minus anywhere except on the list of operators to overload. That's clearly an oversight, caused by unary minus not being very useful to overload at all. In fact, I don't believe that among the horrible abuse of operator overloading I have seen in >20 years was a single case of an overloaded unary minus operator. Nevertheless, thanks for pointing this out. I have now at least [mentioned them](http://stackoverflow.com/a/4421719/140719). As per the rules, I'd made them members. Seems fitting to me. – sbi Dec 22 '14 at 13:52
  • @sbi, the unary minus operator can sometimes be useful when adding two objects is really complex, we write the addition once and then we can implement the subtraction operator by writing a + (-b). This prevents code replication. – mlpo Dec 23 '14 at 15:29
  • Furthermore, I am not sure that the rule is logical, because unary minus operator leaves the operand unchanged and therefore in the same way as addition, it should be non-member function, right? – mlpo Dec 23 '14 at 15:42
  • @mlpo: 1. You could just as well implement the subtraction with `a.data + (-b.data)` without adding a minus operator to the class. (Of course, if the class is supposed to be a number type, then `operator-()` (and `operator+()`) should be part of the interface as per rule #3 [here](http://stackoverflow.com/a/4421708/140719).) 2. As per rule #1 above unary operators should be members, no matter whether they change the object. (Besides prefix increment/decrement I can't think of any that do.) That's because you rarely want to conversions etc. applied to them. – sbi Feb 26 '15 at 08:51
  • @paercebal There are some missing points. 1. `friend` contributes to ADL-only lookup, hence less namespace-scope pollution. This works in despite of the existence of non-public members. So, making something non-member as possible is just not that idiomatic. 2. A simple overload of non-member `operator+=` fails to work on prvalues allowing modifications, but a member overload just works. 3. Diagnostics on non-member overloading failures can be a disaster. Usually not that bad for members. – FrankHB Feb 06 '21 at 08:25
169

Conversion Operators (also known as User Defined Conversions)

In C++ you can create conversion operators, operators that allow the compiler to convert between your types and other defined types. There are two types of conversion operators, implicit and explicit ones.

Implicit Conversion Operators (C++98/C++03 and C++11)

An implicit conversion operator allows the compiler to implicitly convert (like the conversion between int and long) the value of a user-defined type to some other type.

The following is a simple class with an implicit conversion operator:

class my_string {
public:
  operator const char*() const {return data_;} // This is the conversion operator
private:
  const char* data_;
};

Implicit conversion operators, like one-argument constructors, are user-defined conversions. Compilers will grant one user-defined conversion when trying to match a call to an overloaded function.

void f(const char*);

my_string str;
f(str); // same as f( str.operator const char*() )

At first this seems very helpful, but the problem with this is that the implicit conversion even kicks in when it isn’t expected to. In the following code, void f(const char*) will be called because my_string() is not an lvalue, so the first does not match:

void f(my_string&);
void f(const char*);

f(my_string());

Beginners easily get this wrong and even experienced C++ programmers are sometimes surprised because the compiler picks an overload they didn’t suspect. These problems can be mitigated by explicit conversion operators.

Explicit Conversion Operators (C++11)

Unlike implicit conversion operators, explicit conversion operators will never kick in when you don't expect them to. The following is a simple class with an explicit conversion operator:

class my_string {
public:
  explicit operator const char*() const {return data_;}
private:
  const char* data_;
};

Notice the explicit. Now when you try to execute the unexpected code from the implicit conversion operators, you get a compiler error:

prog.cpp: In function ‘int main()’:
prog.cpp:15:18: error: no matching function for call to ‘f(my_string)’
prog.cpp:15:18: note: candidates are:
prog.cpp:11:10: note: void f(my_string&)
prog.cpp:11:10: note:   no known conversion for argument 1 from ‘my_string’ to ‘my_string&’
prog.cpp:12:10: note: void f(const char*)
prog.cpp:12:10: note:   no known conversion for argument 1 from ‘my_string’ to ‘const char*’

To invoke the explicit cast operator, you have to use static_cast, a C-style cast, or a constructor style cast ( i.e. T(value) ).

However, there is one exception to this: The compiler is allowed to implicitly convert to bool. In addition, the compiler is not allowed to do another implicit conversion after it converts to bool (a compiler is allowed to do 2 implicit conversions at a time, but only 1 user-defined conversion at max).

Because the compiler will not cast "past" bool, explicit conversion operators now remove the need for the Safe Bool idiom. For example, smart pointers before C++11 used the Safe Bool idiom to prevent conversions to integral types. In C++11, the smart pointers use an explicit operator instead because the compiler is not allowed to implicitly convert to an integral type after it explicitly converted a type to bool.

Continue to Overloading new and delete.

Community
  • 1
  • 1
JKor
  • 3,634
  • 3
  • 26
  • 36
157

Overloading new and delete

Note: This only deals with the syntax of overloading new and delete, not with the implementation of such overloaded operators. I think that the semantics of overloading new and delete deserve their own FAQ, within the topic of operator overloading I can never do it justice.

Basics

In C++, when you write a new expression like new T(arg) two things happen when this expression is evaluated: First operator new is invoked to obtain raw memory, and then the appropriate constructor of T is invoked to turn this raw memory into a valid object. Likewise, when you delete an object, first its destructor is called, and then the memory is returned to operator delete.
C++ allows you to tune both of these operations: memory management and the construction/destruction of the object at the allocated memory. The latter is done by writing constructors and destructors for a class. Fine-tuning memory management is done by writing your own operator new and operator delete.

The first of the basic rules of operator overloading – don’t do it – applies especially to overloading new and delete. Almost the only reasons to overload these operators are performance problems and memory constraints, and in many cases, other actions, like changes to the algorithms used, will provide a much higher cost/gain ratio than attempting to tweak memory management.

The C++ standard library comes with a set of predefined new and delete operators. The most important ones are these:

void* operator new(std::size_t) throw(std::bad_alloc); 
void  operator delete(void*) throw(); 
void* operator new[](std::size_t) throw(std::bad_alloc); 
void  operator delete[](void*) throw(); 

The first two allocate/deallocate memory for an object, the latter two for an array of objects. If you provide your own versions of these, they will not overload, but replace the ones from the standard library.
If you overload operator new, you should always also overload the matching operator delete, even if you never intend to call it. The reason is that, if a constructor throws during the evaluation of a new expression, the run-time system will return the memory to the operator delete matching the operator new that was called to allocate the memory to create the object in. If you do not provide a matching operator delete, the default one is called, which is almost always wrong.
If you overload new and delete, you should consider overloading the array variants, too.

Placement new

C++ allows new and delete operators to take additional arguments.
So-called placement new allows you to create an object at a certain address which is passed to:

class X { /* ... */ };
char buffer[ sizeof(X) ];
void f()
{ 
  X* p = new(buffer) X(/*...*/);
  // ... 
  p->~X(); // call destructor 
} 

The standard library comes with the appropriate overloads of the new and delete operators for this:

void* operator new(std::size_t,void* p) throw(std::bad_alloc); 
void  operator delete(void* p,void*) throw(); 
void* operator new[](std::size_t,void* p) throw(std::bad_alloc); 
void  operator delete[](void* p,void*) throw(); 

Note that, in the example code for placement new given above, operator delete is never called, unless the constructor of X throws an exception.

You can also overload new and delete with other arguments. As with the additional argument for placement new, these arguments are also listed within parentheses after the keyword new. Merely for historical reasons, such variants are often also called placement new, even if their arguments are not for placing an object at a specific address.

Class-specific new and delete

Most commonly you will want to fine-tune memory management because measurement has shown that instances of a specific class, or of a group of related classes, are created and destroyed often and that the default memory management of the run-time system, tuned for general performance, deals inefficiently in this specific case. To improve this, you can overload new and delete for a specific class:

class my_class { 
  public: 
    // ... 
    void* operator new();
    void  operator delete(void*,std::size_t);
    void* operator new[](size_t);
    void  operator delete[](void*,std::size_t);
    // ... 
}; 

Overloaded thus, new and delete behave like static member functions. For objects of my_class, the std::size_t argument will always be sizeof(my_class). However, these operators are also called for dynamically allocated objects of derived classes, in which case it might be greater than that.

Global new and delete

To overload the global new and delete, simply replace the pre-defined operators of the standard library with our own. However, this rarely ever needs to be done.

Community
  • 1
  • 1
sbi
  • 204,536
  • 44
  • 236
  • 426
  • 12
    I also don't agree that replacing the global operator new and delete is usually for performance: on the contrary, it's usually for bug tracing. – Yttrill Dec 12 '10 at 15:14
  • 1
    You should also note, that if you use an overloaded new operator you're required to also provide a delete operator with matching arguments. You say that in the section on global new/delete where it isn't of much interest. – Yttrill Dec 12 '10 at 15:17
  • @Yttrill: Which tytle are you referring to? This answer's title is "Overloading new and delete". How does this contradict itself? And "confusing description" is quite a broad critique. How am I supposed to know what you expect? – sbi Dec 12 '10 at 19:47
  • @Yttrill: IME overloading `new` and `delete` was rarely done for finding actual bugs. But that might be because I pushed hard for using RAII where I worked, thus eliminating such bugs altogether. – sbi Dec 12 '10 at 19:47
  • @Yttrill:I say about providing a matching operator delete for every operator new in the Basics section. In the section about global new/delete there are only two sentences, and non of them refers to this. What am I missing? – sbi Dec 12 '10 at 19:47
  • 14
    @Yttrill you are confusing things. The *meaning* gets overloaded. What "operator overloading" means is that the meaning is overloaded. It does not mean that literally functions are overloaded, and *in particular* operator new will not overload the Standard's version. @sbi doesn't claim the opposite. It's common to call it "overloading new" much as it is common to say "overloading addition operator". – Johannes Schaub - litb Dec 13 '10 at 04:51
  • What about `nothrow` new ? The rule of thumb is that whenever you overload new, you must write 12 functions: `[array] [{ placement | nothrow }] { new | delete }`. – Alexandre C. Jul 27 '11 at 07:30
  • @Alexandre: This whole FAQ entry is distilled from guidelines I use for teaching C++, and since `nothrow new` is more or less just for legacy stuff, I haven't ever even mentioned it. What would you suggest should be written about it here? – sbi Jul 27 '11 at 07:39
  • 1
    @sbi: See (or better, link to) http://www.gotw.ca/publications/mill15.htm . It is only good practice towards people which sometimes use `nothrow` new. – Alexandre C. Jul 27 '11 at 08:36
  • `new(buffer) X(/*...*/)` what actually guarantees that `buffer` is properly aligned for `X`? – curiousguy Dec 02 '11 at 12:17
  • This part of the FAQ needs improving. One thing: A major reason to overload `operator new` and `delete` is **not** for performance, but usually because of **debugging** and **extremely constrained memory** systems. – unixman83 Mar 23 '12 at 04:57
  • @unixman83: Memory performance is performance, too. `:)` Seriously: You are right, I will add that to the answer. Thanks for pointing it out. I disagree about debugging, though. IME it's much better to use 3rd-party tools than to cook up your own amateur's tools. Also, I consider memory leaks more a problem of your programming style ´, rather than of your tools. I haven't had to hunt for memory leaks in what by now probably is a decade. – sbi Mar 23 '12 at 08:40
  • 1
    "If you do not provide a matching operator delete, the default one is called" -> Actually, if you add any arguments and do not create a matching delete, no operator delete is called at all, and you have a memory leak. (15.2.2, the storage occupied by the object is deallocated only if an appropriate ... operator delete is found) – dascandy Jan 23 '15 at 20:30
51

Why can't operator<< function for streaming objects to std::cout or to a file be a member function?

Let's say you have:

struct Foo
{
   int a;
   double b;

   std::ostream& operator<<(std::ostream& out) const
   {
      return out << a << " " << b;
   }
};

Given that, you cannot use:

Foo f = {10, 20.0};
std::cout << f;

Since operator<< is overloaded as a member function of Foo, the LHS of the operator must be a Foo object. Which means, you will be required to use:

Foo f = {10, 20.0};
f << std::cout

which is very non-intuitive.

If you define it as a non-member function,

struct Foo
{
   int a;
   double b;
};

std::ostream& operator<<(std::ostream& out, Foo const& f)
{
   return out << f.a << " " << f.b;
}

You will be able to use:

Foo f = {10, 20.0};
std::cout << f;

which is very intuitive.

Community
  • 1
  • 1
R Sahu
  • 196,807
  • 13
  • 136
  • 247