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