1# C++ style guide
2
3See also the [C++ codebase README](../../src/README.md) for C++ idioms in the
4Node.js codebase not related to stylistic issues.
5
6## Table of contents
7
8* [Guides and references](#guides-and-references)
9* [Formatting](#formatting)
10  * [Left-leaning (C++ style) asterisks for pointer declarations](#left-leaning-c-style-asterisks-for-pointer-declarations)
11  * [C++ style comments](#c-style-comments)
12  * [2 spaces of indentation for blocks or bodies of conditionals](#2-spaces-of-indentation-for-blocks-or-bodies-of-conditionals)
13  * [4 spaces of indentation for statement continuations](#4-spaces-of-indentation-for-statement-continuations)
14  * [Align function arguments vertically](#align-function-arguments-vertically)
15  * [Initialization lists](#initialization-lists)
16  * [CamelCase for methods, functions, and classes](#camelcase-for-methods-functions-and-classes)
17  * [`snake_case` for local variables and parameters](#snake_case-for-local-variables-and-parameters)
18  * [`snake_case_` for private class fields](#snake_case_-for-private-class-fields)
19  * [`snake_case` for C-like structs](#snake_case-for-c-like-structs)
20  * [Space after `template`](#space-after-template)
21* [Memory management](#memory-management)
22  * [Memory allocation](#memory-allocation)
23  * [Use `nullptr` instead of `NULL` or `0`](#use-nullptr-instead-of-null-or-0)
24  * [Use explicit pointer comparisons](#use-explicit-pointer-comparisons)
25  * [Ownership and smart pointers](#ownership-and-smart-pointers)
26  * [Avoid non-const references](#avoid-non-const-references)
27  * [Use AliasedBuffers to manipulate TypedArrays](#use-aliasedbuffers-to-manipulate-typedarrays)
28* [Others](#others)
29  * [Type casting](#type-casting)
30  * [Using `auto`](#using-auto)
31  * [Do not include `*.h` if `*-inl.h` has already been included](#do-not-include-h-if--inlh-has-already-been-included)
32  * [Avoid throwing JavaScript errors in C++ methods](#avoid-throwing-javascript-errors-in-c)
33    * [Avoid throwing JavaScript errors in nested C++ methods](#avoid-throwing-javascript-errors-in-nested-c-methods)
34
35## Guides and references
36
37The Node.js C++ codebase strives to be consistent in its use of language
38features and idioms, as well as have some specific guidelines for the use of
39runtime features.
40
41Coding guidelines are based on the following guides (highest priority first):
42
431. This document.
442. The [Google C++ Style Guide][].
453. The ISO [C++ Core Guidelines][].
46
47In general, code should follow the C++ Core Guidelines, unless overridden by the
48Google C++ Style Guide or this document. At the moment these guidelines are
49checked manually by reviewers with the goal to validate this with automatic
50tools.
51
52## Formatting
53
54Unfortunately, the C++ linter (based on [Google's `cpplint`][]), which can be
55run explicitly via `make lint-cpp`, does not currently catch a lot of rules that
56are specific to the Node.js C++ code base. This document explains the most
57common of these rules:
58
59### Left-leaning (C++ style) asterisks for pointer declarations
60
61`char* buffer;` instead of `char *buffer;`
62
63### C++ style comments
64
65Use C++ style comments (`//`) for both single-line and multi-line comments.
66Comments should also start with uppercase and finish with a dot.
67
68Examples:
69
70```cpp
71// A single-line comment.
72
73// Multi-line comments
74// should also use C++
75// style comments.
76```
77
78The codebase may contain old C style comments (`/* */`) from before this was the
79preferred style. Feel free to update old comments to the preferred style when
80working on code in the immediate vicinity or when changing/improving those
81comments.
82
83### 2 spaces of indentation for blocks or bodies of conditionals
84
85```cpp
86if (foo)
87  bar();
88```
89
90or
91
92```cpp
93if (foo) {
94  bar();
95  baz();
96}
97```
98
99Braces are optional if the statement body only has one line.
100
101`namespace`s receive no indentation on their own.
102
103### 4 spaces of indentation for statement continuations
104
105```cpp
106VeryLongTypeName very_long_result = SomeValueWithAVeryLongName +
107    SomeOtherValueWithAVeryLongName;
108```
109
110Operators are before the line break in these cases.
111
112### Align function arguments vertically
113
114```cpp
115void FunctionWithAVeryLongName(int parameter_with_a_very_long_name,
116                               double other_parameter_with_a_very_long_name,
117                               ...);
118```
119
120If that doesn't work, break after the `(` and use 4 spaces of indentation:
121
122```cpp
123void FunctionWithAReallyReallyReallyLongNameSeriouslyStopIt(
124    int okay_there_is_no_space_left_in_the_previous_line,
125    ...);
126```
127
128### Initialization lists
129
130Long initialization lists are formatted like this:
131
132```cpp
133HandleWrap::HandleWrap(Environment* env,
134                       Local<Object> object,
135                       uv_handle_t* handle,
136                       AsyncWrap::ProviderType provider)
137    : AsyncWrap(env, object, provider),
138      state_(kInitialized),
139      handle_(handle) {
140```
141
142### CamelCase for methods, functions, and classes
143
144Exceptions are simple getters/setters, which are named `property_name()` and
145`set_property_name()`, respectively.
146
147```cpp
148class FooBar {
149 public:
150  void DoSomething();
151  static void DoSomethingButItsStaticInstead();
152
153  void set_foo_flag(int flag_value);
154  int foo_flag() const;  // Use const-correctness whenever possible.
155};
156```
157
158### `snake_case` for local variables and parameters
159
160```cpp
161int FunctionThatDoesSomething(const char* important_string) {
162  const char* pointer_into_string = important_string;
163}
164```
165
166### `snake_case_` for private class fields
167
168```cpp
169class Foo {
170 private:
171  int counter_ = 0;
172};
173```
174
175### `snake_case` for C-like structs
176
177For plain C-like structs snake\_case can be used.
178
179```cpp
180struct foo_bar {
181  int name;
182};
183```
184
185### Space after `template`
186
187```cpp
188template <typename T>
189class FancyContainer {
190 ...
191};
192```
193
194## Memory management
195
196### Memory allocation
197
198* `Malloc()`, `Calloc()`, etc. from `util.h` abort in Out-of-Memory situations
199* `UncheckedMalloc()`, etc. return `nullptr` in OOM situations
200
201### Use `nullptr` instead of `NULL` or `0`
202
203Further reading in the [C++ Core Guidelines][ES.47].
204
205### Use explicit pointer comparisons
206
207Use explicit comparisons to `nullptr` when testing pointers, i.e.
208`if (foo == nullptr)` instead of `if (foo)` and
209`foo != nullptr` instead of `!foo`.
210
211### Ownership and smart pointers
212
213* [R.20][]: Use `std::unique_ptr` or `std::shared_ptr` to represent ownership
214* [R.21][]: Prefer `unique_ptr` over `shared_ptr` unless you need to share
215  ownership
216
217Use `std::unique_ptr` to make ownership transfer explicit. For example:
218
219```cpp
220std::unique_ptr<Foo> FooFactory();
221void FooConsumer(std::unique_ptr<Foo> ptr);
222```
223
224Since `std::unique_ptr` has only move semantics, passing one by value transfers
225ownership to the callee and invalidates the caller's instance.
226
227Don't use `std::auto_ptr`, it is deprecated ([Reference][cppref_auto_ptr]).
228
229### Avoid non-const references
230
231Using non-const references often obscures which values are changed by an
232assignment. Consider using a pointer instead, which requires more explicit
233syntax to indicate that modifications take place.
234
235```cpp
236class ExampleClass {
237 public:
238  explicit ExampleClass(OtherClass* other_ptr) : pointer_to_other_(other_ptr) {}
239
240  void SomeMethod(const std::string& input_param,
241                  std::string* in_out_param);  // Pointer instead of reference
242
243  const std::string& get_foo() const { return foo_string_; }
244  void set_foo(const std::string& new_value) { foo_string_ = new_value; }
245
246  void ReplaceCharacterInFoo(char from, char to) {
247    // A non-const reference is okay here, because the method name already tells
248    // users that this modifies 'foo_string_' -- if that is not the case,
249    // it can still be better to use an indexed for loop, or leave appropriate
250    // comments.
251    for (char& character : foo_string_) {
252      if (character == from)
253        character = to;
254    }
255  }
256
257 private:
258  std::string foo_string_;
259  // Pointer instead of reference. If this object 'owns' the other object,
260  // this should be a `std::unique_ptr<OtherClass>`; a
261  // `std::shared_ptr<OtherClass>` can also be a better choice.
262  OtherClass* pointer_to_other_;
263};
264```
265
266### Use AliasedBuffers to manipulate TypedArrays
267
268When working with typed arrays that involve direct data modification
269from C++, use an `AliasedBuffer` when possible. The API abstraction and
270the usage scope of `AliasedBuffer` are documented in
271[aliased\_buffer.h][aliased_buffer.h].
272
273```cpp
274// Create an AliasedBuffer.
275AliasedBuffer<uint32_t, v8::Uint32Array> data;
276...
277
278// Modify the data through natural operator semantics.
279data[0] = 12345;
280```
281
282## Others
283
284### Type casting
285
286* Use `static_cast<T>` if casting is required, and it is valid.
287* Use `reinterpret_cast` only when it is necessary.
288* Avoid C-style casts (`(type)value`).
289* `dynamic_cast` does not work because Node.js is built without
290  [Run Time Type Information][].
291
292Further reading:
293
294* [ES.48][]: Avoid casts
295* [ES.49][]: If you must use a cast, use a named cast
296
297### Using `auto`
298
299Being explicit about types is usually preferred over using `auto`.
300
301Use `auto` to avoid type names that are noisy, obvious, or unimportant. When
302doing so, keep in mind that explicit types often help with readability and
303verifying the correctness of code.
304
305```cpp
306for (const auto& item : some_map) {
307  const KeyType& key = item.first;
308  const ValType& value = item.second;
309  // The rest of the loop can now just refer to key and value,
310  // a reader can see the types in question, and we've avoided
311  // the too-common case of extra copies in this iteration.
312}
313```
314
315### Do not include `*.h` if `*-inl.h` has already been included
316
317Do:
318
319```cpp
320#include "util-inl.h"  // already includes util.h
321```
322
323Instead of:
324
325```cpp
326#include "util.h"
327#include "util-inl.h"
328```
329
330### Avoid throwing JavaScript errors in C++
331
332When there is a need to throw errors from a C++ binding method, try to
333return the data necessary for constructing the errors to JavaScript,
334then construct and throw the errors [using `lib/internal/errors.js`][errors].
335
336In general, type-checks on arguments should be done in JavaScript
337before the arguments are passed into C++. Then in the C++ binding, simply using
338`CHECK` assertions to guard against invalid arguments should be enough.
339
340If the return value of the binding cannot be used to signal failures or return
341the necessary data for constructing errors in JavaScript, pass a context object
342to the binding and put the necessary data inside in C++. For example:
343
344```cpp
345void Foo(const FunctionCallbackInfo<Value>& args) {
346  Environment* env = Environment::GetCurrent(args);
347  // Let the JavaScript handle the actual type-checking,
348  // only assertions are placed in C++
349  CHECK_EQ(args.Length(), 2);
350  CHECK(args[0]->IsString());
351  CHECK(args[1]->IsObject());
352
353  int err = DoSomethingWith(args[0].As<String>());
354  if (err) {
355    // Put the data inside the error context
356    Local<Object> ctx = args[1].As<Object>();
357    Local<String> key = FIXED_ONE_BYTE_STRING(env->isolate(), "code");
358    ctx->Set(env->context(), key, err).FromJust();
359  } else {
360    args.GetReturnValue().Set(something_to_return);
361  }
362}
363
364// In the initialize function
365env->SetMethod(target, "foo", Foo);
366```
367
368```js
369exports.foo = function(str) {
370  // Prefer doing the type-checks in JavaScript
371  if (typeof str !== 'string') {
372    throw new errors.codes.ERR_INVALID_ARG_TYPE('str', 'string');
373  }
374
375  const ctx = {};
376  const result = binding.foo(str, ctx);
377  if (ctx.code !== undefined) {
378    throw new errors.codes.ERR_ERROR_NAME(ctx.code);
379  }
380  return result;
381};
382```
383
384#### Avoid throwing JavaScript errors in nested C++ methods
385
386When you need to throw a JavaScript exception from C++ (i.e.
387`isolate()->ThrowException()`), do it as close to the return to JavaScript as
388possible, and not inside of nested C++ calls. Since this changes the JavaScript
389execution state, doing it closest to where it is consumed reduces the chances of
390side effects.
391
392Node.js is built [without C++ exception handling][], so code using `throw` or
393even `try` and `catch` **will** break.
394
395[C++ Core Guidelines]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
396[ES.47]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-nullptr
397[ES.48]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts
398[ES.49]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts-named
399[Google C++ Style Guide]: https://google.github.io/styleguide/cppguide.html
400[Google's `cpplint`]: https://github.com/google/styleguide
401[R.20]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-owner
402[R.21]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-unique
403[Run Time Type Information]: https://en.wikipedia.org/wiki/Run-time_type_information
404[aliased_buffer.h]: https://github.com/nodejs/node/blob/HEAD/src/aliased_buffer.h#L12
405[cppref_auto_ptr]: https://en.cppreference.com/w/cpp/memory/auto_ptr
406[errors]: https://github.com/nodejs/node/blob/HEAD/doc/contributing/using-internal-errors.md
407[without C++ exception handling]: https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_exceptions.html#intro.using.exception.no
408