11cb0ef41Sopenharmony_ci# C++ style guide 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciSee also the [C++ codebase README](../../src/README.md) for C++ idioms in the 41cb0ef41Sopenharmony_ciNode.js codebase not related to stylistic issues. 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ci## Table of contents 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci* [Guides and references](#guides-and-references) 91cb0ef41Sopenharmony_ci* [Formatting](#formatting) 101cb0ef41Sopenharmony_ci * [Left-leaning (C++ style) asterisks for pointer declarations](#left-leaning-c-style-asterisks-for-pointer-declarations) 111cb0ef41Sopenharmony_ci * [C++ style comments](#c-style-comments) 121cb0ef41Sopenharmony_ci * [2 spaces of indentation for blocks or bodies of conditionals](#2-spaces-of-indentation-for-blocks-or-bodies-of-conditionals) 131cb0ef41Sopenharmony_ci * [4 spaces of indentation for statement continuations](#4-spaces-of-indentation-for-statement-continuations) 141cb0ef41Sopenharmony_ci * [Align function arguments vertically](#align-function-arguments-vertically) 151cb0ef41Sopenharmony_ci * [Initialization lists](#initialization-lists) 161cb0ef41Sopenharmony_ci * [CamelCase for methods, functions, and classes](#camelcase-for-methods-functions-and-classes) 171cb0ef41Sopenharmony_ci * [`snake_case` for local variables and parameters](#snake_case-for-local-variables-and-parameters) 181cb0ef41Sopenharmony_ci * [`snake_case_` for private class fields](#snake_case_-for-private-class-fields) 191cb0ef41Sopenharmony_ci * [`snake_case` for C-like structs](#snake_case-for-c-like-structs) 201cb0ef41Sopenharmony_ci * [Space after `template`](#space-after-template) 211cb0ef41Sopenharmony_ci* [Memory management](#memory-management) 221cb0ef41Sopenharmony_ci * [Memory allocation](#memory-allocation) 231cb0ef41Sopenharmony_ci * [Use `nullptr` instead of `NULL` or `0`](#use-nullptr-instead-of-null-or-0) 241cb0ef41Sopenharmony_ci * [Use explicit pointer comparisons](#use-explicit-pointer-comparisons) 251cb0ef41Sopenharmony_ci * [Ownership and smart pointers](#ownership-and-smart-pointers) 261cb0ef41Sopenharmony_ci * [Avoid non-const references](#avoid-non-const-references) 271cb0ef41Sopenharmony_ci * [Use AliasedBuffers to manipulate TypedArrays](#use-aliasedbuffers-to-manipulate-typedarrays) 281cb0ef41Sopenharmony_ci* [Others](#others) 291cb0ef41Sopenharmony_ci * [Type casting](#type-casting) 301cb0ef41Sopenharmony_ci * [Using `auto`](#using-auto) 311cb0ef41Sopenharmony_ci * [Do not include `*.h` if `*-inl.h` has already been included](#do-not-include-h-if--inlh-has-already-been-included) 321cb0ef41Sopenharmony_ci * [Avoid throwing JavaScript errors in C++ methods](#avoid-throwing-javascript-errors-in-c) 331cb0ef41Sopenharmony_ci * [Avoid throwing JavaScript errors in nested C++ methods](#avoid-throwing-javascript-errors-in-nested-c-methods) 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ci## Guides and references 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ciThe Node.js C++ codebase strives to be consistent in its use of language 381cb0ef41Sopenharmony_cifeatures and idioms, as well as have some specific guidelines for the use of 391cb0ef41Sopenharmony_ciruntime features. 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ciCoding guidelines are based on the following guides (highest priority first): 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ci1. This document. 441cb0ef41Sopenharmony_ci2. The [Google C++ Style Guide][]. 451cb0ef41Sopenharmony_ci3. The ISO [C++ Core Guidelines][]. 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ciIn general, code should follow the C++ Core Guidelines, unless overridden by the 481cb0ef41Sopenharmony_ciGoogle C++ Style Guide or this document. At the moment these guidelines are 491cb0ef41Sopenharmony_cichecked manually by reviewers with the goal to validate this with automatic 501cb0ef41Sopenharmony_citools. 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ci## Formatting 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ciUnfortunately, the C++ linter (based on [Google's `cpplint`][]), which can be 551cb0ef41Sopenharmony_cirun explicitly via `make lint-cpp`, does not currently catch a lot of rules that 561cb0ef41Sopenharmony_ciare specific to the Node.js C++ code base. This document explains the most 571cb0ef41Sopenharmony_cicommon of these rules: 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci### Left-leaning (C++ style) asterisks for pointer declarations 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci`char* buffer;` instead of `char *buffer;` 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci### C++ style comments 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ciUse C++ style comments (`//`) for both single-line and multi-line comments. 661cb0ef41Sopenharmony_ciComments should also start with uppercase and finish with a dot. 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ciExamples: 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ci```cpp 711cb0ef41Sopenharmony_ci// A single-line comment. 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ci// Multi-line comments 741cb0ef41Sopenharmony_ci// should also use C++ 751cb0ef41Sopenharmony_ci// style comments. 761cb0ef41Sopenharmony_ci``` 771cb0ef41Sopenharmony_ci 781cb0ef41Sopenharmony_ciThe codebase may contain old C style comments (`/* */`) from before this was the 791cb0ef41Sopenharmony_cipreferred style. Feel free to update old comments to the preferred style when 801cb0ef41Sopenharmony_ciworking on code in the immediate vicinity or when changing/improving those 811cb0ef41Sopenharmony_cicomments. 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci### 2 spaces of indentation for blocks or bodies of conditionals 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ci```cpp 861cb0ef41Sopenharmony_ciif (foo) 871cb0ef41Sopenharmony_ci bar(); 881cb0ef41Sopenharmony_ci``` 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_cior 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci```cpp 931cb0ef41Sopenharmony_ciif (foo) { 941cb0ef41Sopenharmony_ci bar(); 951cb0ef41Sopenharmony_ci baz(); 961cb0ef41Sopenharmony_ci} 971cb0ef41Sopenharmony_ci``` 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ciBraces are optional if the statement body only has one line. 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ci`namespace`s receive no indentation on their own. 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci### 4 spaces of indentation for statement continuations 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ci```cpp 1061cb0ef41Sopenharmony_ciVeryLongTypeName very_long_result = SomeValueWithAVeryLongName + 1071cb0ef41Sopenharmony_ci SomeOtherValueWithAVeryLongName; 1081cb0ef41Sopenharmony_ci``` 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ciOperators are before the line break in these cases. 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ci### Align function arguments vertically 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci```cpp 1151cb0ef41Sopenharmony_civoid FunctionWithAVeryLongName(int parameter_with_a_very_long_name, 1161cb0ef41Sopenharmony_ci double other_parameter_with_a_very_long_name, 1171cb0ef41Sopenharmony_ci ...); 1181cb0ef41Sopenharmony_ci``` 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ciIf that doesn't work, break after the `(` and use 4 spaces of indentation: 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci```cpp 1231cb0ef41Sopenharmony_civoid FunctionWithAReallyReallyReallyLongNameSeriouslyStopIt( 1241cb0ef41Sopenharmony_ci int okay_there_is_no_space_left_in_the_previous_line, 1251cb0ef41Sopenharmony_ci ...); 1261cb0ef41Sopenharmony_ci``` 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci### Initialization lists 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ciLong initialization lists are formatted like this: 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci```cpp 1331cb0ef41Sopenharmony_ciHandleWrap::HandleWrap(Environment* env, 1341cb0ef41Sopenharmony_ci Local<Object> object, 1351cb0ef41Sopenharmony_ci uv_handle_t* handle, 1361cb0ef41Sopenharmony_ci AsyncWrap::ProviderType provider) 1371cb0ef41Sopenharmony_ci : AsyncWrap(env, object, provider), 1381cb0ef41Sopenharmony_ci state_(kInitialized), 1391cb0ef41Sopenharmony_ci handle_(handle) { 1401cb0ef41Sopenharmony_ci``` 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci### CamelCase for methods, functions, and classes 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ciExceptions are simple getters/setters, which are named `property_name()` and 1451cb0ef41Sopenharmony_ci`set_property_name()`, respectively. 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci```cpp 1481cb0ef41Sopenharmony_ciclass FooBar { 1491cb0ef41Sopenharmony_ci public: 1501cb0ef41Sopenharmony_ci void DoSomething(); 1511cb0ef41Sopenharmony_ci static void DoSomethingButItsStaticInstead(); 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_ci void set_foo_flag(int flag_value); 1541cb0ef41Sopenharmony_ci int foo_flag() const; // Use const-correctness whenever possible. 1551cb0ef41Sopenharmony_ci}; 1561cb0ef41Sopenharmony_ci``` 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci### `snake_case` for local variables and parameters 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_ci```cpp 1611cb0ef41Sopenharmony_ciint FunctionThatDoesSomething(const char* important_string) { 1621cb0ef41Sopenharmony_ci const char* pointer_into_string = important_string; 1631cb0ef41Sopenharmony_ci} 1641cb0ef41Sopenharmony_ci``` 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ci### `snake_case_` for private class fields 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ci```cpp 1691cb0ef41Sopenharmony_ciclass Foo { 1701cb0ef41Sopenharmony_ci private: 1711cb0ef41Sopenharmony_ci int counter_ = 0; 1721cb0ef41Sopenharmony_ci}; 1731cb0ef41Sopenharmony_ci``` 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci### `snake_case` for C-like structs 1761cb0ef41Sopenharmony_ci 1771cb0ef41Sopenharmony_ciFor plain C-like structs snake\_case can be used. 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ci```cpp 1801cb0ef41Sopenharmony_cistruct foo_bar { 1811cb0ef41Sopenharmony_ci int name; 1821cb0ef41Sopenharmony_ci}; 1831cb0ef41Sopenharmony_ci``` 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_ci### Space after `template` 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci```cpp 1881cb0ef41Sopenharmony_citemplate <typename T> 1891cb0ef41Sopenharmony_ciclass FancyContainer { 1901cb0ef41Sopenharmony_ci ... 1911cb0ef41Sopenharmony_ci}; 1921cb0ef41Sopenharmony_ci``` 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci## Memory management 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ci### Memory allocation 1971cb0ef41Sopenharmony_ci 1981cb0ef41Sopenharmony_ci* `Malloc()`, `Calloc()`, etc. from `util.h` abort in Out-of-Memory situations 1991cb0ef41Sopenharmony_ci* `UncheckedMalloc()`, etc. return `nullptr` in OOM situations 2001cb0ef41Sopenharmony_ci 2011cb0ef41Sopenharmony_ci### Use `nullptr` instead of `NULL` or `0` 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ciFurther reading in the [C++ Core Guidelines][ES.47]. 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci### Use explicit pointer comparisons 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ciUse explicit comparisons to `nullptr` when testing pointers, i.e. 2081cb0ef41Sopenharmony_ci`if (foo == nullptr)` instead of `if (foo)` and 2091cb0ef41Sopenharmony_ci`foo != nullptr` instead of `!foo`. 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_ci### Ownership and smart pointers 2121cb0ef41Sopenharmony_ci 2131cb0ef41Sopenharmony_ci* [R.20][]: Use `std::unique_ptr` or `std::shared_ptr` to represent ownership 2141cb0ef41Sopenharmony_ci* [R.21][]: Prefer `unique_ptr` over `shared_ptr` unless you need to share 2151cb0ef41Sopenharmony_ci ownership 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_ciUse `std::unique_ptr` to make ownership transfer explicit. For example: 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ci```cpp 2201cb0ef41Sopenharmony_cistd::unique_ptr<Foo> FooFactory(); 2211cb0ef41Sopenharmony_civoid FooConsumer(std::unique_ptr<Foo> ptr); 2221cb0ef41Sopenharmony_ci``` 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_ciSince `std::unique_ptr` has only move semantics, passing one by value transfers 2251cb0ef41Sopenharmony_ciownership to the callee and invalidates the caller's instance. 2261cb0ef41Sopenharmony_ci 2271cb0ef41Sopenharmony_ciDon't use `std::auto_ptr`, it is deprecated ([Reference][cppref_auto_ptr]). 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci### Avoid non-const references 2301cb0ef41Sopenharmony_ci 2311cb0ef41Sopenharmony_ciUsing non-const references often obscures which values are changed by an 2321cb0ef41Sopenharmony_ciassignment. Consider using a pointer instead, which requires more explicit 2331cb0ef41Sopenharmony_cisyntax to indicate that modifications take place. 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ci```cpp 2361cb0ef41Sopenharmony_ciclass ExampleClass { 2371cb0ef41Sopenharmony_ci public: 2381cb0ef41Sopenharmony_ci explicit ExampleClass(OtherClass* other_ptr) : pointer_to_other_(other_ptr) {} 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci void SomeMethod(const std::string& input_param, 2411cb0ef41Sopenharmony_ci std::string* in_out_param); // Pointer instead of reference 2421cb0ef41Sopenharmony_ci 2431cb0ef41Sopenharmony_ci const std::string& get_foo() const { return foo_string_; } 2441cb0ef41Sopenharmony_ci void set_foo(const std::string& new_value) { foo_string_ = new_value; } 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_ci void ReplaceCharacterInFoo(char from, char to) { 2471cb0ef41Sopenharmony_ci // A non-const reference is okay here, because the method name already tells 2481cb0ef41Sopenharmony_ci // users that this modifies 'foo_string_' -- if that is not the case, 2491cb0ef41Sopenharmony_ci // it can still be better to use an indexed for loop, or leave appropriate 2501cb0ef41Sopenharmony_ci // comments. 2511cb0ef41Sopenharmony_ci for (char& character : foo_string_) { 2521cb0ef41Sopenharmony_ci if (character == from) 2531cb0ef41Sopenharmony_ci character = to; 2541cb0ef41Sopenharmony_ci } 2551cb0ef41Sopenharmony_ci } 2561cb0ef41Sopenharmony_ci 2571cb0ef41Sopenharmony_ci private: 2581cb0ef41Sopenharmony_ci std::string foo_string_; 2591cb0ef41Sopenharmony_ci // Pointer instead of reference. If this object 'owns' the other object, 2601cb0ef41Sopenharmony_ci // this should be a `std::unique_ptr<OtherClass>`; a 2611cb0ef41Sopenharmony_ci // `std::shared_ptr<OtherClass>` can also be a better choice. 2621cb0ef41Sopenharmony_ci OtherClass* pointer_to_other_; 2631cb0ef41Sopenharmony_ci}; 2641cb0ef41Sopenharmony_ci``` 2651cb0ef41Sopenharmony_ci 2661cb0ef41Sopenharmony_ci### Use AliasedBuffers to manipulate TypedArrays 2671cb0ef41Sopenharmony_ci 2681cb0ef41Sopenharmony_ciWhen working with typed arrays that involve direct data modification 2691cb0ef41Sopenharmony_cifrom C++, use an `AliasedBuffer` when possible. The API abstraction and 2701cb0ef41Sopenharmony_cithe usage scope of `AliasedBuffer` are documented in 2711cb0ef41Sopenharmony_ci[aliased\_buffer.h][aliased_buffer.h]. 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_ci```cpp 2741cb0ef41Sopenharmony_ci// Create an AliasedBuffer. 2751cb0ef41Sopenharmony_ciAliasedBuffer<uint32_t, v8::Uint32Array> data; 2761cb0ef41Sopenharmony_ci... 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_ci// Modify the data through natural operator semantics. 2791cb0ef41Sopenharmony_cidata[0] = 12345; 2801cb0ef41Sopenharmony_ci``` 2811cb0ef41Sopenharmony_ci 2821cb0ef41Sopenharmony_ci## Others 2831cb0ef41Sopenharmony_ci 2841cb0ef41Sopenharmony_ci### Type casting 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ci* Use `static_cast<T>` if casting is required, and it is valid. 2871cb0ef41Sopenharmony_ci* Use `reinterpret_cast` only when it is necessary. 2881cb0ef41Sopenharmony_ci* Avoid C-style casts (`(type)value`). 2891cb0ef41Sopenharmony_ci* `dynamic_cast` does not work because Node.js is built without 2901cb0ef41Sopenharmony_ci [Run Time Type Information][]. 2911cb0ef41Sopenharmony_ci 2921cb0ef41Sopenharmony_ciFurther reading: 2931cb0ef41Sopenharmony_ci 2941cb0ef41Sopenharmony_ci* [ES.48][]: Avoid casts 2951cb0ef41Sopenharmony_ci* [ES.49][]: If you must use a cast, use a named cast 2961cb0ef41Sopenharmony_ci 2971cb0ef41Sopenharmony_ci### Using `auto` 2981cb0ef41Sopenharmony_ci 2991cb0ef41Sopenharmony_ciBeing explicit about types is usually preferred over using `auto`. 3001cb0ef41Sopenharmony_ci 3011cb0ef41Sopenharmony_ciUse `auto` to avoid type names that are noisy, obvious, or unimportant. When 3021cb0ef41Sopenharmony_cidoing so, keep in mind that explicit types often help with readability and 3031cb0ef41Sopenharmony_civerifying the correctness of code. 3041cb0ef41Sopenharmony_ci 3051cb0ef41Sopenharmony_ci```cpp 3061cb0ef41Sopenharmony_cifor (const auto& item : some_map) { 3071cb0ef41Sopenharmony_ci const KeyType& key = item.first; 3081cb0ef41Sopenharmony_ci const ValType& value = item.second; 3091cb0ef41Sopenharmony_ci // The rest of the loop can now just refer to key and value, 3101cb0ef41Sopenharmony_ci // a reader can see the types in question, and we've avoided 3111cb0ef41Sopenharmony_ci // the too-common case of extra copies in this iteration. 3121cb0ef41Sopenharmony_ci} 3131cb0ef41Sopenharmony_ci``` 3141cb0ef41Sopenharmony_ci 3151cb0ef41Sopenharmony_ci### Do not include `*.h` if `*-inl.h` has already been included 3161cb0ef41Sopenharmony_ci 3171cb0ef41Sopenharmony_ciDo: 3181cb0ef41Sopenharmony_ci 3191cb0ef41Sopenharmony_ci```cpp 3201cb0ef41Sopenharmony_ci#include "util-inl.h" // already includes util.h 3211cb0ef41Sopenharmony_ci``` 3221cb0ef41Sopenharmony_ci 3231cb0ef41Sopenharmony_ciInstead of: 3241cb0ef41Sopenharmony_ci 3251cb0ef41Sopenharmony_ci```cpp 3261cb0ef41Sopenharmony_ci#include "util.h" 3271cb0ef41Sopenharmony_ci#include "util-inl.h" 3281cb0ef41Sopenharmony_ci``` 3291cb0ef41Sopenharmony_ci 3301cb0ef41Sopenharmony_ci### Avoid throwing JavaScript errors in C++ 3311cb0ef41Sopenharmony_ci 3321cb0ef41Sopenharmony_ciWhen there is a need to throw errors from a C++ binding method, try to 3331cb0ef41Sopenharmony_cireturn the data necessary for constructing the errors to JavaScript, 3341cb0ef41Sopenharmony_cithen construct and throw the errors [using `lib/internal/errors.js`][errors]. 3351cb0ef41Sopenharmony_ci 3361cb0ef41Sopenharmony_ciIn general, type-checks on arguments should be done in JavaScript 3371cb0ef41Sopenharmony_cibefore the arguments are passed into C++. Then in the C++ binding, simply using 3381cb0ef41Sopenharmony_ci`CHECK` assertions to guard against invalid arguments should be enough. 3391cb0ef41Sopenharmony_ci 3401cb0ef41Sopenharmony_ciIf the return value of the binding cannot be used to signal failures or return 3411cb0ef41Sopenharmony_cithe necessary data for constructing errors in JavaScript, pass a context object 3421cb0ef41Sopenharmony_cito the binding and put the necessary data inside in C++. For example: 3431cb0ef41Sopenharmony_ci 3441cb0ef41Sopenharmony_ci```cpp 3451cb0ef41Sopenharmony_civoid Foo(const FunctionCallbackInfo<Value>& args) { 3461cb0ef41Sopenharmony_ci Environment* env = Environment::GetCurrent(args); 3471cb0ef41Sopenharmony_ci // Let the JavaScript handle the actual type-checking, 3481cb0ef41Sopenharmony_ci // only assertions are placed in C++ 3491cb0ef41Sopenharmony_ci CHECK_EQ(args.Length(), 2); 3501cb0ef41Sopenharmony_ci CHECK(args[0]->IsString()); 3511cb0ef41Sopenharmony_ci CHECK(args[1]->IsObject()); 3521cb0ef41Sopenharmony_ci 3531cb0ef41Sopenharmony_ci int err = DoSomethingWith(args[0].As<String>()); 3541cb0ef41Sopenharmony_ci if (err) { 3551cb0ef41Sopenharmony_ci // Put the data inside the error context 3561cb0ef41Sopenharmony_ci Local<Object> ctx = args[1].As<Object>(); 3571cb0ef41Sopenharmony_ci Local<String> key = FIXED_ONE_BYTE_STRING(env->isolate(), "code"); 3581cb0ef41Sopenharmony_ci ctx->Set(env->context(), key, err).FromJust(); 3591cb0ef41Sopenharmony_ci } else { 3601cb0ef41Sopenharmony_ci args.GetReturnValue().Set(something_to_return); 3611cb0ef41Sopenharmony_ci } 3621cb0ef41Sopenharmony_ci} 3631cb0ef41Sopenharmony_ci 3641cb0ef41Sopenharmony_ci// In the initialize function 3651cb0ef41Sopenharmony_cienv->SetMethod(target, "foo", Foo); 3661cb0ef41Sopenharmony_ci``` 3671cb0ef41Sopenharmony_ci 3681cb0ef41Sopenharmony_ci```js 3691cb0ef41Sopenharmony_ciexports.foo = function(str) { 3701cb0ef41Sopenharmony_ci // Prefer doing the type-checks in JavaScript 3711cb0ef41Sopenharmony_ci if (typeof str !== 'string') { 3721cb0ef41Sopenharmony_ci throw new errors.codes.ERR_INVALID_ARG_TYPE('str', 'string'); 3731cb0ef41Sopenharmony_ci } 3741cb0ef41Sopenharmony_ci 3751cb0ef41Sopenharmony_ci const ctx = {}; 3761cb0ef41Sopenharmony_ci const result = binding.foo(str, ctx); 3771cb0ef41Sopenharmony_ci if (ctx.code !== undefined) { 3781cb0ef41Sopenharmony_ci throw new errors.codes.ERR_ERROR_NAME(ctx.code); 3791cb0ef41Sopenharmony_ci } 3801cb0ef41Sopenharmony_ci return result; 3811cb0ef41Sopenharmony_ci}; 3821cb0ef41Sopenharmony_ci``` 3831cb0ef41Sopenharmony_ci 3841cb0ef41Sopenharmony_ci#### Avoid throwing JavaScript errors in nested C++ methods 3851cb0ef41Sopenharmony_ci 3861cb0ef41Sopenharmony_ciWhen you need to throw a JavaScript exception from C++ (i.e. 3871cb0ef41Sopenharmony_ci`isolate()->ThrowException()`), do it as close to the return to JavaScript as 3881cb0ef41Sopenharmony_cipossible, and not inside of nested C++ calls. Since this changes the JavaScript 3891cb0ef41Sopenharmony_ciexecution state, doing it closest to where it is consumed reduces the chances of 3901cb0ef41Sopenharmony_ciside effects. 3911cb0ef41Sopenharmony_ci 3921cb0ef41Sopenharmony_ciNode.js is built [without C++ exception handling][], so code using `throw` or 3931cb0ef41Sopenharmony_cieven `try` and `catch` **will** break. 3941cb0ef41Sopenharmony_ci 3951cb0ef41Sopenharmony_ci[C++ Core Guidelines]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines 3961cb0ef41Sopenharmony_ci[ES.47]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-nullptr 3971cb0ef41Sopenharmony_ci[ES.48]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts 3981cb0ef41Sopenharmony_ci[ES.49]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts-named 3991cb0ef41Sopenharmony_ci[Google C++ Style Guide]: https://google.github.io/styleguide/cppguide.html 4001cb0ef41Sopenharmony_ci[Google's `cpplint`]: https://github.com/google/styleguide 4011cb0ef41Sopenharmony_ci[R.20]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-owner 4021cb0ef41Sopenharmony_ci[R.21]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-unique 4031cb0ef41Sopenharmony_ci[Run Time Type Information]: https://en.wikipedia.org/wiki/Run-time_type_information 4041cb0ef41Sopenharmony_ci[aliased_buffer.h]: https://github.com/nodejs/node/blob/HEAD/src/aliased_buffer.h#L12 4051cb0ef41Sopenharmony_ci[cppref_auto_ptr]: https://en.cppreference.com/w/cpp/memory/auto_ptr 4061cb0ef41Sopenharmony_ci[errors]: https://github.com/nodejs/node/blob/HEAD/doc/contributing/using-internal-errors.md 4071cb0ef41Sopenharmony_ci[without C++ exception handling]: https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_exceptions.html#intro.using.exception.no 408