-
Notifications
You must be signed in to change notification settings - Fork 31.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
doc: add basic C++ style guide #16090
Changes from all commits
a4417a5
39ab867
b6a028c
66a546d
68176fe
8b289f1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
# C++ Style Guide | ||
|
||
Unfortunately, the C++ linter (based on | ||
[Google’s `cpplint`](https://github.com/google/styleguide)), which can be run | ||
explicitly via `make lint-cpp`, does not currently catch a lot of rules that are | ||
specific to the Node.js C++ code base. This document explains the most common of | ||
these rules: | ||
|
||
## Left-leaning (C++ style) asterisks for pointer declarations | ||
|
||
`char* buffer;` instead of `char *buffer;` | ||
|
||
## 2 spaces of indentation for blocks or bodies of conditionals | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also for loops (unless conditionals includes loops).
Now that I am thinking about it, I am not sure we use loops without parens... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, conditionals includes conditional loops. :) Anyway, I don’t think the current phrasing leaves anybody thinking that we use indentation other than 2 spaces. |
||
|
||
```c++ | ||
if (foo) | ||
bar(); | ||
``` | ||
|
||
or | ||
|
||
```c++ | ||
if (foo) { | ||
bar(); | ||
baz(); | ||
} | ||
``` | ||
|
||
Braces are optional if the statement body only has one line. | ||
|
||
`namespace`s receive no indentation on their own. | ||
|
||
## 4 spaces of indentation for statement continuations | ||
|
||
```c++ | ||
VeryLongTypeName very_long_result = SomeValueWithAVeryLongName + | ||
SomeOtherValueWithAVeryLongName; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the linter doesn't currently catch whether the operation is at the end of the line or the beginning of the next line. couple examples: // ternary
int r = true ?
1 : 0;
int r = true
? 1 : 0;
// conditional
if (foo &&
bar) { }
if (foo
&& bar) { } specify this? @addaleax /cc @bnoordhuis There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Ternary operator: we don't have a hard rule, I think, but IMO if it doesn't fit on a single line, you should be using an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. re: placement of |
||
``` | ||
|
||
Operators are before the line break in these cases. | ||
|
||
## Align function arguments vertically | ||
|
||
```c++ | ||
void FunctionWithAVeryLongName(int parameter_with_a_very_long_name, | ||
double other_parameter_with_a_very_long_name, | ||
...); | ||
``` | ||
|
||
If that doesn’t work, break after the `(` and use 4 spaces of indentation: | ||
|
||
```c++ | ||
void FunctionWithAReallyReallyReallyLongNameSeriouslyStopIt( | ||
int okay_there_is_no_space_left_in_the_previous_line, | ||
...); | ||
``` | ||
|
||
## Initialization lists | ||
|
||
Long initialization lists are formatted like this: | ||
|
||
```c++ | ||
HandleWrap::HandleWrap(Environment* env, | ||
Local<Object> object, | ||
uv_handle_t* handle, | ||
AsyncWrap::ProviderType provider) | ||
: AsyncWrap(env, object, provider), | ||
state_(kInitialized), | ||
handle_(handle) { | ||
``` | ||
|
||
## CamelCase for methods, functions and classes | ||
|
||
Exceptions are simple getters/setters, which are named `property_name()` and | ||
`set_property_name()`, respectively. | ||
|
||
```c++ | ||
class FooBar { | ||
public: | ||
void DoSomething(); | ||
static void DoSomethingButItsStaticInstead(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We also use |
||
|
||
void set_foo_flag(int flag_value); | ||
int foo_flag() const; // Use const-correctness whenever possible. | ||
}; | ||
``` | ||
|
||
## snake\_case for local variables and parameters | ||
|
||
```c++ | ||
int FunctionThatDoesSomething(const char* important_string) { | ||
const char* pointer_into_string = important_string; | ||
} | ||
``` | ||
|
||
## snake\_case\_ for private class fields | ||
|
||
```c++ | ||
class Foo { | ||
private: | ||
int counter_ = 0; | ||
}; | ||
``` | ||
|
||
## Space after `template` | ||
|
||
```c++ | ||
template <typename T> | ||
class FancyContainer { | ||
... | ||
} | ||
``` | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. another common pattern is how we handle indentation of initialization lists. example: HandleWrap::HandleWrap(Environment* env,
Local<Object> object,
uv_handle_t* handle,
AsyncWrap::ProviderType provider)
: AsyncWrap(env, object, provider),
state_(kInitialized),
handle_(handle) { basically: if the initialization list does not fit on one line then it returns to the next line, indents 4 spaces then starts with the colon. Every additional member in the list starts on a new line and indented 6 spaced, to align with the first member in the list. |
||
## Type casting | ||
|
||
- Always avoid C-style casts (`(type)value`) | ||
- `dynamic_cast` does not work because RTTI is not enabled | ||
- Use `static_cast` for casting whenever it works | ||
- `reinterpret_cast` is okay if `static_cast` is not appropriate | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it may be worth mentioning usage of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. const_cast: should be used sparingly and only when it's still conceptually const afterwards. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there is nothing specific to Node about using |
||
|
||
## Memory allocation | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could these two be clarified... slightly? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you have any specific question? I realize this isn’t helpful when it comes to which-do-I-use, but then again we don’t really follow any specific rules for this right now. (I assume @bnoordhuis is a fan of just aborting in OOM situations, me not so much. 😄) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, ok. On re-reading it I think I understand, maybe we could clarify the wording like so: - Use `Malloc()`, `Calloc()`, etc. from `util.h` to cause an abort in Out-of-Memory situations.
- Use `UncheckedMalloc()`, etc. to return a `nullptr` in OOM situations. |
||
|
||
- `Malloc()`, `Calloc()`, etc. from `util.h` abort in Out-of-Memory situations | ||
- `UncheckedMalloc()`, etc. return `nullptr` in OOM situations | ||
|
||
## `nullptr` instead of `NULL` or `0` | ||
|
||
What it says in the title. | ||
|
||
## Avoid throwing JavaScript errors in nested C++ methods | ||
|
||
If you need to throw JavaScript errors from a C++ binding method, try to do it | ||
at the top level and not inside of nested calls. | ||
|
||
A lot of code inside Node.js is written so that typechecking etc. is performed | ||
in JavaScript. | ||
|
||
Using C++ `throw` is not allowed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No doubt this is correct, but it always bothers me with multiple variables:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd just declare one variable per line