cheatsheets

Operators and operator overloading

precendence

name

operator

arity

associativity

overloading

notes

1

scope resolution

x::y, ::x

1-2

LtR

-

2

suffix increment

x++

1

LtR

member

2

suffix decrement

x--

1

LtR

member

2

functional cast

T(x)

1

LtR

member

2

functional cast

T{x}

1

LtR

member

C++11

2

function call

x()

1+

LtR

member

2

subscript

x[]

2

LtR

member

2

member access

x.y

1

LtR

-

2

member access

x->y

1

LtR

member

has return type restrictions

3

prefix increment

++x

1

RtL

member

3

prefix decrement

--x

1

RtL

member

3

unary plus

+x

1

RtL

both

3

unary minus

-x

1

RtL

both

3

logical NOT

!x

1

RtL

member

3

bitwise NOT

~x

1

RtL

member

3

C-style cast

(T) x

1

RtL

member

3

dereference

*x

1

RtL

member

3

address-of

&x

1

RtL

member

overloading discouraged

3

size-of

sizeof T, sizeof x

1

RtL

-

3

await expression

co_await x

1

RtL

member

C++20

3

dynamic memory allocation

new

1+

RtL

both

3

dynamic memory allocation

new[]

1+

RtL

both

3

dynamic memory deallocation

delete

1

RtL

both

3

dynamic memory deallocation

delete[]

1

RtL

both

4

pointer-to-member access

x.*y

1

LtR

-

4

pointer-to-member access

x->*y

1

LtR

member

5

multiplication

x * y

2

LtR

recommended free

5

division

x / y

2

LtR

recommended free

5

remainer

x % y

2

LtR

recommended free

6

addition

x + y

2

LtR

recommended free

6

subtraction

x - y

2

LtR

recommended free

7

bitwise left shift

x << y

2

LtR

recommended free

7

bitwise right shift

x >> y

2

LtR

recommended free

8

three-way comparison, spaceship

x <=> y

2

LtR

both

C++20

9

less than

x < y

2

LtR

recommended free

9

less than or equal to

x <= y

2

LtR

recommended free

9

greater than

x > y

2

LtR

recommended free

9

greater than or equal to

x >= y

2

LtR

recommended free

10

equal to

x == y

2

LtR

recommended free

10

not equal to

x != y

2

LtR

recommended free

11

bitwise AND

x & y

2

LtR

recommended free

12

bitwise XOR

x ^ y

2

LtR

recommended free

13

bitwise OR

x | y

2

LtR

recommended free

14

logical AND

x && y

2

LtR

recommended free

overloads lose short-circuit evaluation

15

logical OR

x || y

2

LtR

recommended free

overloads lose short-circuit evaluation

16

ternary conditional

x ? y : z

3

RtL

-

16

throw

throw, throw x

0-1

RtL

-

16

yield expression

co_yield x

1

RtL

-

C++20

16

direct assignment

x = y

2

RtL

member

16

compound assignment by sum

x += y

2

RtL

recommended member

16

compound assignment by difference

x -= y

2

RtL

recommended member

16

compound assignment by product

x *= y

2

RtL

recommended member

16

compound assignment by quotient

x /= y

2

RtL

recommended member

16

compound assignment by remainder

x %= y

2

RtL

recommended member

16

compound assignment by bitwise left shift

x <<= y

2

RtL

recommended member

16

compound assignment by bitwise right shift

x >>= y

2

RtL

recommended member

16

compound assignment by bitwise AND

x &= y

2

RtL

recommended member

16

compound assignment by bitwise XOR

x ^= y

2

RtL

recommended member

16

compound assignment by bitwise OR

x |= y

2

RtL

recommended member

17

comma

x, y

2

LtR

recommended free

overloading discouraged

-

user-defined literal

""x

1

-

free

C++11

-

static cast

static_cast<T>(x)

1

-

member

C++11

-

dynamic cast

dynamic_cast<T>(x)

1

-

-

C++11

-

const cast

const_cast<T>(x)

1

-

-

C++11

-

reinterpret cast

reinterpret_cast<T>(x)

1

-

-

C++11

-

size-of parameter pack

sizeof...(T), sizeof...(x)

1

-

-

C++11

-

typeid

typeid(T), typeid(x)

1

-

-

C++11

-

noexcept

noexcept(x)

1

-

-

C++11

-

alignof

alignof(T), alignof(x)

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 like x.y and x->y the arity is 1 because y 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 to x @ (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))
	{}