• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 [aliased_buffer.h][].
271
272```cpp
273// Create an AliasedBuffer.
274AliasedBuffer<uint32_t, v8::Uint32Array> data;
275...
276
277// Modify the data through natural operator semantics.
278data[0] = 12345;
279```
280
281## Others
282
283### Type casting
284
285* Use `static_cast<T>` if casting is required, and it is valid.
286* Use `reinterpret_cast` only when it is necessary.
287* Avoid C-style casts (`(type)value`).
288* `dynamic_cast` does not work because Node.js is built without
289  [Run Time Type Information][].
290
291Further reading:
292
293* [ES.48][]: Avoid casts
294* [ES.49][]: If you must use a cast, use a named cast
295
296### Using `auto`
297
298Being explicit about types is usually preferred over using `auto`.
299
300Use `auto` to avoid type names that are noisy, obvious, or unimportant. When
301doing so, keep in mind that explicit types often help with readability and
302verifying the correctness of code.
303
304```cpp
305for (const auto& item : some_map) {
306  const KeyType& key = item.first;
307  const ValType& value = item.second;
308  // The rest of the loop can now just refer to key and value,
309  // a reader can see the types in question, and we've avoided
310  // the too-common case of extra copies in this iteration.
311}
312```
313
314### Do not include `*.h` if `*-inl.h` has already been included
315
316Do:
317
318```cpp
319#include "util-inl.h"  // already includes util.h
320```
321
322Instead of:
323
324```cpp
325#include "util.h"
326#include "util-inl.h"
327```
328
329### Avoid throwing JavaScript errors in C++
330
331When there is a need to throw errors from a C++ binding method, try to
332return the data necessary for constructing the errors to JavaScript,
333then construct and throw the errors [using `lib/internal/errors.js`][errors].
334
335In general, type-checks on arguments should be done in JavaScript
336before the arguments are passed into C++. Then in the C++ binding, simply using
337`CHECK` assertions to guard against invalid arguments should be enough.
338
339If the return value of the binding cannot be used to signal failures or return
340the necessary data for constructing errors in JavaScript, pass a context object
341to the binding and put the necessary data inside in C++. For example:
342
343```cpp
344void Foo(const FunctionCallbackInfo<Value>& args) {
345  Environment* env = Environment::GetCurrent(args);
346  // Let the JavaScript handle the actual type-checking,
347  // only assertions are placed in C++
348  CHECK_EQ(args.Length(), 2);
349  CHECK(args[0]->IsString());
350  CHECK(args[1]->IsObject());
351
352  int err = DoSomethingWith(args[0].As<String>());
353  if (err) {
354    // Put the data inside the error context
355    Local<Object> ctx = args[1].As<Object>();
356    Local<String> key = FIXED_ONE_BYTE_STRING(env->isolate(), "code");
357    ctx->Set(env->context(), key, err).FromJust();
358  } else {
359    args.GetReturnValue().Set(something_to_return);
360  }
361}
362
363// In the initialize function
364env->SetMethod(target, "foo", Foo);
365```
366
367```js
368exports.foo = function(str) {
369  // Prefer doing the type-checks in JavaScript
370  if (typeof str !== 'string') {
371    throw new errors.codes.ERR_INVALID_ARG_TYPE('str', 'string');
372  }
373
374  const ctx = {};
375  const result = binding.foo(str, ctx);
376  if (ctx.code !== undefined) {
377    throw new errors.codes.ERR_ERROR_NAME(ctx.code);
378  }
379  return result;
380};
381```
382
383#### Avoid throwing JavaScript errors in nested C++ methods
384
385When you need to throw a JavaScript exception from C++ (i.e.
386`isolate()->ThrowException()`), do it as close to the return to JavaScript as
387possible, and not inside of nested C++ calls. Since this changes the JavaScript
388execution state, doing it closest to where it is consumed reduces the chances of
389side effects.
390
391Node.js is built [without C++ exception handling][], so code using `throw` or
392even `try` and `catch` **will** break.
393
394[C++ Core Guidelines]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
395[ES.47]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-nullptr
396[ES.48]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts
397[ES.49]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts-named
398[Google C++ Style Guide]: https://google.github.io/styleguide/cppguide.html
399[Google’s `cpplint`]: https://github.com/google/styleguide
400[R.20]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-owner
401[R.21]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-unique
402[Run Time Type Information]: https://en.wikipedia.org/wiki/Run-time_type_information
403[aliased_buffer.h]: https://github.com/nodejs/node/blob/HEAD/src/aliased_buffer.h#L12
404[cppref_auto_ptr]: https://en.cppreference.com/w/cpp/memory/auto_ptr
405[errors]: https://github.com/nodejs/node/blob/HEAD/doc/guides/using-internal-errors.md
406[without C++ exception handling]: https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_exceptions.html#intro.using.exception.no
407