summaryrefslogtreecommitdiff
path: root/CPP_STYLE_GUIDE.md
blob: 6266ee03b7c5382e9fe7e2487244076bdaffaad4 (plain)
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# C++ Style Guide

## Table of Contents

* [Formatting](#formatting)
  * [Left-leaning (C++ style) asterisks for pointer declarations](#left-leaning-c-style-asterisks-for-pointer-declarations)
  * [C++ style comments](#c-style-comments)
  * [2 spaces of indentation for blocks or bodies of conditionals](#2-spaces-of-indentation-for-blocks-or-bodies-of-conditionals)
  * [4 spaces of indentation for statement continuations](#4-spaces-of-indentation-for-statement-continuations)
  * [Align function arguments vertically](#align-function-arguments-vertically)
  * [Initialization lists](#initialization-lists)
  * [CamelCase for methods, functions, and classes](#camelcase-for-methods-functions-and-classes)
  * [snake\_case for local variables and parameters](#snake_case-for-local-variables-and-parameters)
  * [snake\_case\_ for private class fields](#snake_case_-for-private-class-fields)
  * [Space after `template`](#space-after-template)
* [Memory Management](#memory-management)
  * [Memory allocation](#memory-allocation)
  * [Use `nullptr` instead of `NULL` or `0`](#use-nullptr-instead-of-null-or-0)
  * [Ownership and Smart Pointers](#ownership-and-smart-pointers)
* [Others](#others)
  * [Type casting](#type-casting)
  * [Do not include `*.h` if `*-inl.h` has already been included](#do-not-include-h-if--inlh-has-already-been-included)
  * [Avoid throwing JavaScript errors in nested C++ methods](#avoid-throwing-javascript-errors-in-nested-c-methods)

Unfortunately, the C++ linter (based on
[Google’s `cpplint`](https://github.com/google/styleguide)), which can be run
explicitly via `make lint-cpp`, does not currently catch a lot of rules that are
specific to the Node.js C++ code base. This document explains the most common of
these rules:

## Formatting

## Left-leaning (C++ style) asterisks for pointer declarations

`char* buffer;` instead of `char *buffer;`

## C++ style comments

Use C++ style comments (`//`) for both single-line and multi-line comments.
Comments should also start with uppercase and finish with a dot.

Examples:

```c++
// A single-line comment.

// Multi-line comments
// should also use C++
// style comments.
```

The codebase may contain old C style comments (`/* */`) from before this was the
preferred style. Feel free to update old comments to the preferred style when
working on code in the immediate vicinity or when changing/improving those
comments.

## 2 spaces of indentation for blocks or bodies of conditionals

```c++
if (foo)
  bar();
```

or

```c++
if (foo) {
  bar();
  baz();
}
```

Braces are optional if the statement body only has one line.

`namespace`s receive no indentation on their own.

## 4 spaces of indentation for statement continuations

```c++
VeryLongTypeName very_long_result = SomeValueWithAVeryLongName +
    SomeOtherValueWithAVeryLongName;
```

Operators are before the line break in these cases.

## Align function arguments vertically

```c++
void FunctionWithAVeryLongName(int parameter_with_a_very_long_name,
                               double other_parameter_with_a_very_long_name,
                               ...);
```

If that doesn’t work, break after the `(` and use 4 spaces of indentation:

```c++
void FunctionWithAReallyReallyReallyLongNameSeriouslyStopIt(
    int okay_there_is_no_space_left_in_the_previous_line,
    ...);
```

## Initialization lists

Long initialization lists are formatted like this:

```c++
HandleWrap::HandleWrap(Environment* env,
                       Local<Object> object,
                       uv_handle_t* handle,
                       AsyncWrap::ProviderType provider)
    : AsyncWrap(env, object, provider),
      state_(kInitialized),
      handle_(handle) {
```

## CamelCase for methods, functions, and classes

Exceptions are simple getters/setters, which are named `property_name()` and
`set_property_name()`, respectively.

```c++
class FooBar {
 public:
  void DoSomething();
  static void DoSomethingButItsStaticInstead();

  void set_foo_flag(int flag_value);
  int foo_flag() const;  // Use const-correctness whenever possible.
};
```

## snake\_case for local variables and parameters

```c++
int FunctionThatDoesSomething(const char* important_string) {
  const char* pointer_into_string = important_string;
}
```

## snake\_case\_ for private class fields

```c++
class Foo {
 private:
  int counter_ = 0;
};
```

## Space after `template`

```c++
template <typename T>
class FancyContainer {
 ...
}
```
## Memory Management

## Memory allocation

- `Malloc()`, `Calloc()`, etc. from `util.h` abort in Out-of-Memory situations
- `UncheckedMalloc()`, etc. return `nullptr` in OOM situations

## Use `nullptr` instead of `NULL` or `0`

What it says in the title.

## Ownership and Smart Pointers

"Smart" pointers are classes that act like pointers, e.g.
by overloading the `*` and `->` operators. Some smart pointer types can be
used to automate ownership bookkeeping, to ensure these responsibilities are
met. `std::unique_ptr` is a smart pointer type introduced in C++11, which
expresses exclusive ownership of a dynamically allocated object; the object
is deleted when the `std::unique_ptr` goes out of scope. It cannot be
copied, but can be moved to represent ownership transfer.
`std::shared_ptr` is a smart pointer type that expresses shared ownership of a
dynamically allocated object. `std::shared_ptr`s can be copied; ownership
of the object is shared among all copies, and the object
is deleted when the last `std::shared_ptr` is destroyed.

Prefer to use `std::unique_ptr` to make ownership
transfer explicit. For example:

```cpp
std::unique_ptr<Foo> FooFactory();
void FooConsumer(std::unique_ptr<Foo> ptr);
```

Never use `std::auto_ptr`. Instead, use `std::unique_ptr`.

## Others

## Type casting

- Always avoid C-style casts (`(type)value`)
- `dynamic_cast` does not work because RTTI is not enabled
- Use `static_cast` for casting whenever it works
- `reinterpret_cast` is okay if `static_cast` is not appropriate

## Do not include `*.h` if `*-inl.h` has already been included

Do

```cpp
#include "util-inl.h"  // already includes util.h
```

instead of

```cpp
#include "util.h"
#include "util-inl.h"
```

## Avoid throwing JavaScript errors in nested C++ methods

If you need to throw JavaScript errors from a C++ binding method, try to do it
at the top level and not inside of nested calls.

A lot of code inside Node.js is written so that typechecking etc. is performed
in JavaScript.

Using C++ `throw` is not allowed.