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