cheatsheets
Operators and operator overloading
precendence |
name |
operator |
arity |
associativity |
overloading |
notes |
---|---|---|---|---|---|---|
1 |
scope resolution |
|
1-2 |
LtR |
- |
|
2 |
suffix increment |
|
1 |
LtR |
member |
|
2 |
suffix decrement |
|
1 |
LtR |
member |
|
2 |
functional cast |
|
1 |
LtR |
member |
|
2 |
functional cast |
|
1 |
LtR |
member |
C++11 |
2 |
function call |
|
1+ |
LtR |
member |
|
2 |
subscript |
|
2 |
LtR |
member |
|
2 |
member access |
|
1 |
LtR |
- |
|
2 |
member access |
|
1 |
LtR |
member |
has return type restrictions |
3 |
prefix increment |
|
1 |
RtL |
member |
|
3 |
prefix decrement |
|
1 |
RtL |
member |
|
3 |
unary plus |
|
1 |
RtL |
both |
|
3 |
unary minus |
|
1 |
RtL |
both |
|
3 |
logical NOT |
|
1 |
RtL |
member |
|
3 |
bitwise NOT |
|
1 |
RtL |
member |
|
3 |
C-style cast |
|
1 |
RtL |
member |
|
3 |
dereference |
|
1 |
RtL |
member |
|
3 |
address-of |
|
1 |
RtL |
member |
overloading discouraged |
3 |
size-of |
|
1 |
RtL |
- |
|
3 |
await expression |
|
1 |
RtL |
member |
C++20 |
3 |
dynamic memory allocation |
|
1+ |
RtL |
both |
|
3 |
dynamic memory allocation |
|
1+ |
RtL |
both |
|
3 |
dynamic memory deallocation |
|
1 |
RtL |
both |
|
3 |
dynamic memory deallocation |
|
1 |
RtL |
both |
|
4 |
pointer-to-member access |
|
1 |
LtR |
- |
|
4 |
pointer-to-member access |
|
1 |
LtR |
member |
|
5 |
multiplication |
|
2 |
LtR |
recommended free |
|
5 |
division |
|
2 |
LtR |
recommended free |
|
5 |
remainer |
|
2 |
LtR |
recommended free |
|
6 |
addition |
|
2 |
LtR |
recommended free |
|
6 |
subtraction |
|
2 |
LtR |
recommended free |
|
7 |
bitwise left shift |
|
2 |
LtR |
recommended free |
|
7 |
bitwise right shift |
|
2 |
LtR |
recommended free |
|
8 |
three-way comparison, spaceship |
|
2 |
LtR |
both |
C++20 |
9 |
less than |
|
2 |
LtR |
recommended free |
|
9 |
less than or equal to |
|
2 |
LtR |
recommended free |
|
9 |
greater than |
|
2 |
LtR |
recommended free |
|
9 |
greater than or equal to |
|
2 |
LtR |
recommended free |
|
10 |
equal to |
|
2 |
LtR |
recommended free |
|
10 |
not equal to |
|
2 |
LtR |
recommended free |
|
11 |
bitwise AND |
|
2 |
LtR |
recommended free |
|
12 |
bitwise XOR |
|
2 |
LtR |
recommended free |
|
13 |
bitwise OR |
|
2 |
LtR |
recommended free |
|
14 |
logical AND |
|
2 |
LtR |
recommended free |
overloads lose short-circuit evaluation |
15 |
logical OR |
|
2 |
LtR |
recommended free |
overloads lose short-circuit evaluation |
16 |
ternary conditional |
|
3 |
RtL |
- |
|
16 |
throw |
|
0-1 |
RtL |
- |
|
16 |
yield expression |
|
1 |
RtL |
- |
C++20 |
16 |
direct assignment |
|
2 |
RtL |
member |
|
16 |
compound assignment by sum |
|
2 |
RtL |
recommended member |
|
16 |
compound assignment by difference |
|
2 |
RtL |
recommended member |
|
16 |
compound assignment by product |
|
2 |
RtL |
recommended member |
|
16 |
compound assignment by quotient |
|
2 |
RtL |
recommended member |
|
16 |
compound assignment by remainder |
|
2 |
RtL |
recommended member |
|
16 |
compound assignment by bitwise left shift |
|
2 |
RtL |
recommended member |
|
16 |
compound assignment by bitwise right shift |
|
2 |
RtL |
recommended member |
|
16 |
compound assignment by bitwise AND |
|
2 |
RtL |
recommended member |
|
16 |
compound assignment by bitwise XOR |
|
2 |
RtL |
recommended member |
|
16 |
compound assignment by bitwise OR |
|
2 |
RtL |
recommended member |
|
17 |
comma |
|
2 |
LtR |
recommended free |
overloading discouraged |
- |
user-defined literal |
|
1 |
- |
free |
C++11 |
- |
static cast |
|
1 |
- |
member |
C++11 |
- |
dynamic cast |
|
1 |
- |
- |
C++11 |
- |
const cast |
|
1 |
- |
- |
C++11 |
- |
reinterpret cast |
|
1 |
- |
- |
C++11 |
- |
size-of parameter pack |
|
1 |
- |
- |
C++11 |
- |
typeid |
|
1 |
- |
- |
C++11 |
- |
noexcept |
|
1 |
- |
- |
C++11 |
- |
alignof |
|
1 |
- |
- |
C++11 |
Legend:
-
precendence - C++ has no formal precendence of operators. Their precendence is implicitly defined by the grammar.
If multiple operators have the same precedence they are applied according to their associativity.
Operators with no precedence in the table are never ambiguous.
arity - number of operands (including
*this
if appropriate). In cases likex.y
andx->y
the arity is 1 becausey
does not contribute to the operator's output.-
associativity:
left-to-right:
x @ y @ z
is equivalent to(x @ y) @ z
right-to-left:
x @ y @ z
is equivalent tox @ (y @ z)
-
overloading:
free - must be a free function
member - must be a member function
both - can be both free function and member function, no recommendation
recommended free - can be both a free function and a member function, recommended free function
recommended member - can be both a free function and a member function, recommended member function
- - can not be overloaded
Notes:
Overloading convertion operator affects all functional casts, C-style cast and
static_cast
.
RAII - canonical rule of 5 implementations
Below are idiomatic implementations of classes that implement the Rule of 5.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
#include <utility> #include <cassert> #include <algorithm> class copyable { public: copyable() = default; copyable(const copyable& other) : m_size(other.m_size) { if (m_size > 0) { m_data = new double[m_size]; copy_from(other.m_data, other.m_size); } } copyable(copyable&& other) noexcept { swap(*this, other); } // copy and swap idiom (4 special member functions + swap) copyable& operator=(copyable other) noexcept { swap(*this, other); return *this; } // (no move assignment because the overload above is optimal for both) ~copyable() { clear(); } friend void swap(copyable& lhs, copyable& rhs) noexcept { std::swap(lhs.m_data, rhs.m_data); std::swap(lhs.m_size, rhs.m_size); } void clear() noexcept { delete m_data; m_size = 0; } private: void copy_from(const double* data, int size) { assert(m_size >= size); std::copy(data, data + size, m_data); } double* m_data = nullptr; int m_size = 0; }; class moveable { moveable() = default; moveable(const moveable& other) = delete; moveable(moveable&& other) noexcept { swap(*this, other); } moveable& operator=(const moveable& other) = delete; moveable& operator=(moveable&& other) noexcept { swap(*this, other); return *this; } ~moveable() { clear(); } friend void swap(moveable& lhs, moveable& rhs) noexcept { std::swap(lhs.m_data, rhs.m_data); std::swap(lhs.m_size, rhs.m_size); } void clear() noexcept { delete m_data; m_size = 0; } private: double* m_data = nullptr; int m_size = 0; }; |
Depending on the class exact planned behavior (some may not have default constructor and default member initializers), a canonical implementation can replace swaps with member initializer lists using std::exchange
:
1 2 3 4 |
moveable(moveable&& other) noexcept : m_data(std::exchange(other.m_data, nullptr)) , m_size(std::exchange(other.m_size, 0)) {} |
Initialization
meme summary: https://i.imgur.com/3wlxtI0.gifv
-
rules cheatsheets:
-
actual specification cheatsheets: