• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# C++ Coding Style Guide
2
3## Purpose
4Rules are not perfect. They might disable useful features in specific situations and therefore affect code implementation. However, the purpose of developing rules is to get more benefits for most programmers. If a rule cannot be followed in your team operation, we can improve the rule together.
5
6Before referring to this coding style guide, you are expected to have the following basic capabilities of the C++programming language:
7
81. Have a general knowledge of ISO standards for C++.
92. Be familiar with the basic features of C++, including those of C++ 03/11/14/17.
103. Have a general knowledge of the C++ standard library.
11
12## General Principles
13Code must meet the requirements for readability, maintainability, security, reliability, testability, efficiency, and portability while ensuring functionality correctness.
14
15## Key Points
161. C++ programming style, such as naming and typesetting.
172. C++ modular design, including how to design header files, classes, interfaces, and functions.
183. Best practices of C++ features, including constants, type casting, resource management, and templates.
194. Best practices of modern C++, including conventions that can improve code maintainability and reliability in C++ 11/14/17.
205. This coding style guide is preferentially applicable to C++17.
21
22## Conventions
23**Rule**: Conventions that must be followed during programming.
24
25**Rec**: Conventions that must be considered during programming.
26
27This document is applicable to standard C++ versions (C++ 03/11/14/17) unless otherwise specified.
28
29## Exceptions
30It is necessary to understand the reason for these conventions and try to comply with them, no matter if they are rules or recommendations.
31
32However, some rules and recommendations have exceptions.
33
34The only acceptable exceptions are those that do not violate the general principles and provide appropriate reasons for the exception.
35
36Try to avoid exceptions because they affect the code consistency. Exceptions to 'Rules' should be very rare.
37
38The style consistency principle is preferred in the following case:
39
40When you modify open-source or third-party code, comply with their respective code specifications.
41
42# 2 Naming
43## General Naming Rules
44__CamelCase__
45CamelCase is the practice of writing compound words or phrases so that each word or abbreviation in the phrase begins with a capital letter, and with no intervening spaces or punctuation.
46
47There are two conventions: UpperCamelCase and lowerCamelCase.
48
49
50| Type                                     | Naming Style                             |
51| ---------------------------------------- | ---------------------------------------- |
52| Class, struct, enumeration, union, scope name| UpperCamelCase                           |
53| Functions (including global functions, scope functions, and member functions) | UpperCamelCase                           |
54| Global variables (including variables of the global and namespace scopes, and class static variables), local variables, function parameters, and class, struct, and union member variables | lowerCamelCase                           |
55| Macro, constant, enumerated value, goto tag| All capitalized, separated by underscores (\_)|
56
57Note:
58
59**Constant** in the above table refers to the variable that is of the basic data type, enumeration type, and string type and modified by **const** or **constexpr** under the global scope, the namespace scope, and the scope of a static member of a class, excluding arrays and other variables.
60
61**Variable** indicates the variables excluding those defined in **Constant**. These variables use the lowerCamelCase style.
62
63## File Naming
64### Rule 2.2.1 Use .cpp as the C++ file name extension and .h as the header file name extension.
65It is recommended that you use .h as the file name extension of a header file so that the header file is compatible with C and C++.
66
67It is recommended that you use .cpp as the file name extension of an implementation file. In this way, you can easily distinguish C++ code from C code.
68
69At present, there are some other file name extensions used by programmers:
70
71- Header files:  .hh, .hpp, .hxx
72- Implementation files: .cc, .cxx, .C
73
74If your project team uses a specific file name extension, you can continue to use it and keep the style consistent.
75
76This document uses .h and .cpp extensions.
77
78
79### Rule 2.2.2 Keep C++ file names the same as the class name.
80The names of the C++ header file and the C++ implementation file must be the same as the class name. Use the unix\_like style and keep the style consistent.
81
82For example, if there is a class named DatabaseConnection, the corresponding file names are as follows:
83- database_connection.h
84- database_connection.cpp
85
86The naming rules of struct, namespace, and enumeration definition files are similar to the rules above.
87
88## Function Naming
89Functions are named in the UpperCamelCase style. Generally, the verb or verb-object structure is used.
90```cpp
91class List {
92public:
93	void AddElement(const Element& element);
94	Element GetElement(const unsigned int index) const;
95	bool IsEmpty() const;
96};
97
98namespace Utils {
99    void DeleteUser();
100}
101```
102
103## Type Naming
104
105Types are named in the UpperCamelCase style.
106
107All types, such as classes, structs, unions, typedefs, and enumerations, use the same conventions. Example:
108
109```cpp
110// Classes, structs, and unions
111class UrlTable { ...
112class UrlTableTester { ...
113struct UrlTableProperties { ...
114union Packet { ...
115
116// typedefs
117typedef std::map<std::string, UrlTableProperties*> PropertiesMap;
118
119// Enums
120enum UrlTableErrors { ...
121```
122
123For namespace naming, UpperCamelCase is recommended.
124```cpp
125// Namespaces
126namespace OsUtils {
127
128namespace FileUtils {
129
130}
131
132}
133```
134
135
136### Rec 2.4.1 Do not abuse typedef or #define to set alias for the basic data types.
137Unless otherwise specified, do not use typedef or #define to redefine basic data types.
138
139The basic data types found in the `<cstdint>` header file are preferable.
140
141| Signed Type | Unsigned Type | Description                              |
142| ----------- | ------------- | ---------------------------------------- |
143| int8_t      | uint8_t       | The signed or unsigned 8-bit integer type. |
144| int16_t     | uint16_t      | The signed or unsigned 16-bit integer type. |
145| int32_t     | uint32_t      | The signed or unsigned 32-bit integer type. |
146| int64_t     | uint64_t      | The signed or unsigned 64-bit integer type. |
147| intptr_t    | uintptr_t     | The signed or unsigned integer type large enough to hold a pointer. |
148
149
150## Variable Naming
151General variables, including global variables, function parameters, local variables, and member variables, are named in the lowerCamelCase style.
152```cpp
153std::string tableName;  // Good: Recommended style.
154std::string tablename;  // Bad: Forbidden style.
155std::string path;       // Good: When there is only one word, lowerCamelCase (all lowercase) is used.
156```
157
158### Rule 2.5.1 Add the prefix 'g_' to global variables. Do not add a prefix to a static variable.
159Global variables should be used as little as possible, and special attention should be paid to their use. This prefix highlights global variables so that developers can be more careful when handling them.
160- Global static variables and global variables are named in the same way.
161- Static variables in functions and common local variables are named in the same way.
162- Static member variables in classes and common member variables are named in the same way.
163
164```cpp
165int g_activeConnectCount;
166
167void Func()
168{
169    static int packetCount = 0;
170    ...
171}
172```
173
174### Rule 2.5.2 Name member variables in classes in the unix\_like style.
175
176```cpp
177class Foo {
178private:
179    std::string fileName_;   // Add the underscore (\_) as the suffix, similar to the K&R naming style.
180};
181```
182Use the lowerCamelCase style and do not add prefixes or suffixes to name a member variable of the struct or union type. Keep the naming style consistent with that for a local variable.
183
184## Macro, Constant, and Enum Naming
185Use uppercase letters separated by underscores (\_) for macro names and enumerated values.
186In the global scope, constants of named and unnamed namespaces and static member constants should be capitalized and separated with underscores (\_).Local constants and ordinary const member variables use the lowerCamelCase naming style.
187
188```cpp
189#define MAX(a, b) (((a) < (b))? (b): (a)) // Example of naming a macro only.
190
191enum BaseColor {    // Note: The enum type name is in the UpperCamelCase style, whereas the enumerated value is in uppercase letters separated by underscores (\_).
192    RED,
193    DARK_RED,
194    GREEN,
195    LIGHT_GREEN
196};
197
198int Func(...)
199{
200    const unsigned int bufferSize = 100;    // Local variable
201    char *p = new char[bufferSize];
202    ...
203}
204
205namespace Utils {
206	const unsigned int DEFAULT_FILE_SIZE_KB = 200;        // Global variable
207}
208
209```
210
211# 3 Formatting
212
213## Line Length
214
215### Rule 3.1.1 Include 120 characters or less in each line.
216If the line of code exceeds the permitted length, wrap the line appropriately.
217
218Exceptions:
219- If a line of comment contains a command or URL of more than 120 characters, you can keep the line for easy copy, paste, and search using the grep command.
220- The #include and #error statements are allowed to exceed the line length requirement. However, you should try to avoid this.
221- The error information in preprocessor directives can exceed the permitted length.
222  Put the error information of preprocessor directives in one line to facilitate reading and understanding even if the line contains more than 120 characters.
223```cpp
224#ifndef XXX_YYY_ZZZ
225#error Header aaaa/bbbb/cccc/abc.h must only be included after xxxx/yyyy/zzzz/xyz.h, because xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
226#endif
227```
228
229## Indentation
230
231### Rule 3.2.1 Use spaces to indent and indent 4 spaces at a time.
232Only spaces can be used for indentation. Four spaces are indented each time. Do not use the Tab character to indent.
233
234Currently, almost all integrated development environments (IDEs) support automatic conversion of a Tab input to four spaces. Configure your IDE to support indentation with spaces.
235
236## Braces
237### Rule 3.3.1 Use the K&R indentation style.
238__K&R style__
239
240While wrapping a line, the left brace of the function (excluding the lambda statement) starts a new line and takes a single line. Other left braces are placed at the end of the line along with the statement.
241
242The right brace takes a single line, unless it is followed by the rest of the same statement, such as `while` in the `do` statement, `else` or `else if` in the `if` statement, a comma, or a semicolon.
243
244Example:
245```cpp
246struct MyType {     // The left brace is placed at the end of the line along with the statement, and one space is used for indentation.
247    ...
248};
249
250int Foo(int a)
251{                   // The left brace of the function starts a new line, and nothing else is placed on the line.
252    if (...) {
253        ...
254    } else {
255        ...
256    }
257}
258```
259The reasons for recommending this style are as follows:
260
261- Code is more compact.
262- Placing the brace at the end of the statement makes the code more continuous in reading rhythm than starting a new line.
263- This style complies with mainstream norms and habits of programming languages.
264- Most modern IDEs have an automatic code indentation, alignment and display. Placing the brace at the end of a line does not impact understanding.
265
266
267If no function body is inside the braces, the braces can be put on the same line.
268```cpp
269class MyClass {
270public:
271    MyClass() : value_(0) {}
272
273private:
274    int value_;
275};
276```
277
278## Function Declarations and Definitions
279
280### Rule 3.4.1 Keep the return type and function name of the function declaration or definition in the same line, and align the function parameter list appropriately if it needs to be wrapped.
281When a function is declared and defined, the return value type of the function should be in the same line as the function name. When the function parameter list is wrapped, it should be aligned appropriately.
282The left parenthesis of a parameter list is always in the same line as the function name. The right parenthesis always follows the last parameter.
283
284Example:
285```cpp
286ReturnType FunctionName(ArgType paramName1, ArgType paramName2)   // Good: All are in the same line.
287{
288    ...
289}
290
291ReturnType VeryVeryVeryLongFunctionName(ArgType paramName1,     // Each added parameter starts on a new line because the line length limit is exceeded.
292                                        ArgType paramName2,     // Good: aligned with the previous parameter.
293                                        ArgType paramName3)
294{
295    ...
296}
297
298ReturnType LongFunctionName(ArgType paramName1, ArgType paramName2, // Parameters are wrapped because the line length limit is exceeded.
299    ArgType paramName3, ArgType paramName4, ArgType paramName5)     // Good: After the line break, 4 spaces are used for indentation.
300{
301    ...
302}
303
304ReturnType ReallyReallyReallyReallyLongFunctionName(            // The line length cannot accommodate even the first parameter, and a line break is required.
305    ArgType paramName1, ArgType paramName2, ArgType paramName3) // Good: After the line break, 4 spaces are used for indentation.
306{
307    ...
308}
309```
310
311## Function Calls
312### Rule 3.5.1 A function call parameter list should be placed on one line. When the parameter list exceeds the line length and requires a line break, the parameters should be properly aligned.
313A function call parameter list should be placed on one line. When the parameter list exceeds the line length and requires a line break, the parameters should be properly aligned.
314
315The left parenthesis always follows the function name, and the right parenthesis always follows the last parameter.
316
317The following are examples of proper line breaks:
318```cpp
319ReturnType result = FunctionName(paramName1, paramName2);   // Good: All function parameters are on one line.
320
321ReturnType result = FunctionName(paramName1,
322                                 paramName2,                // Good: aligned with the previous parameter
323                                 paramName3);
324
325ReturnType result = FunctionName(paramName1, paramName2,
326    paramName3, paramName4, paramName5);                    // Good: Parameters are wrapped. After the line break, 4 spaces are used for indentation.
327
328ReturnType result = VeryVeryVeryLongFunctionName(           // The line length cannot accommodate even the first parameter, and a line break is required.
329    paramName1, paramName2, paramName3);                    // After the line break, 4 spaces are used for indentation.
330```
331
332If some of the parameters called by a function are associated with each other, you can group them for better understanding.
333```cpp
334// Good: The parameters in each line represent a group of data structures with strong correlation. They are placed on a line for ease of understanding.
335int result = DealWithStructureLikeParams(left.x, left.y,     // A group of related parameters.
336                                         right.x, right.y);  // Another group of related parameters.
337```
338
339## if Statements
340
341### Rule 3.6.1 Use braces to include an if statement.
342We require that all if statements use braces, even if there is only one statement.
343
344Reasons:
345- The logic is intuitive and easy to read.
346- It is less prone to mistakes when new code is added to the existing if statement.
347- If function-like macros are used in a conditional statement, it is less prone to mistakes (in case the braces are missing when macros are defined).
348
349```cpp
350if (objectIsNotExist) {         // Good: Braces are added to a single-line conditional statement.
351    return CreateNewObject();
352}
353```
354### Rule 3.6.2 Place if, else, and else if keywords on separate lines.
355If there are multiple branches in a conditional statement, they should be placed on separate lines.
356
357Good example:
358
359```cpp
360if (someConditions) {
361    DoSomething();
362    ...
363} else {  // Good: Put the if and else keywords on separate lines.
364    ...
365}
366```
367
368Bad example:
369
370```cpp
371if (someConditions) { ... } else { ... } // Bad: The if and else keywords are put on the same line.
372```
373
374## Loop Statements
375### Rule 3.7.1 Use braces after loop statements.
376Similar to if statements, we require that the for and while loop statements contain braces, even if the loop body is empty or there is only one loop statement.
377```cpp
378for (int i = 0; i < someRange; i++) {   // Good: Braces are used.
379    DoSomething();
380}
381```
382```cpp
383while (condition) {} // Good: The while loop body is empty. Braces should be used.
384```
385```cpp
386while (condition) {
387    continue; // Good: The continue keyword highlights the end of the empty loop. Braces should be used.
388}
389```
390
391Bad example:
392```cpp
393for (int i = 0; i < someRange; i++)
394    DoSomething();      // Bad: Braces are mandatory.
395```
396```cpp
397while (someCondition) ; // Bad: Using a semicolon here will make people misunderstand that it is a part of the while statement and not the end to it.
398```
399
400## Switch Statements
401### Rule 3.8.1 Indent case and default in a switch statement with four spaces.
402The indentation style of the switch statement is as follows:
403```cpp
404switch (var) {
405    case 0:             // Good: Indented
406        DoSomething1(); // Good: Indented
407        break;
408    case 1: {           // Good: Braces are added.
409        DoSomething2();
410        break;
411    }
412    default:
413        break;
414}
415```
416
417```cpp
418switch (var) {
419case 0:                 // Bad: case is not indented.
420    DoSomething();
421    break;
422default:                // Bad: default is not indented.
423    break;
424}
425```
426
427## Expressions
428
429### Rec 3.9.1 Keep a consistent line break style for expressions and ensure that operators are placed at the end of a line.
430A long expression that does not meet the line length requirement must be wrapped appropriately.
431
432Generally, the expression is wrapped at an operator of a lower priority or a connector, and the operator or connector is placed at the end of the line.
433
434Placing these at the end of a line indicates that the operation is to be continued on the next line.
435Example:
436
437// Assume that the first line exceeds the length limit.
438```cpp
439if (currentValue > threshold &&  // Good: After the line break, the logical-AND operators are placed at the end of the line.
440    someCondition) {
441    DoSomething();
442    ...
443}
444
445int result = reallyReallyLongVariableName1 +    // Good
446             reallyReallyLongVariableName2;
447```
448After an expression is wrapped, ensure that the lines are aligned appropriately or indented with 4 spaces. See the following example.
449
450```cpp
451int sum = longVariableName1 + longVariableName2 + longVariableName3 +
452    longVariableName4 + longVariableName5 + longVariableName6;         // Good: indented with 4 spaces
453
454int sum = longVariableName1 + longVariableName2 + longVariableName3 +
455          longVariableName4 + longVariableName5 + longVariableName6;   // Good: The lines are aligned.
456```
457## Variable Assignment
458
459### Rule 3.10.1 Multiple variable definitions and assignment statements cannot be written on one line.
460Each line should have only one variable initialization statement. It is easier to read and understand.
461
462```cpp
463int maxCount = 10;
464bool isCompleted = false;
465```
466
467Bad example:
468
469```cpp
470int maxCount = 10; bool isCompleted = false; // Bad: Multiple variable initialization statements must be separated on different lines. Each variable initialization statement occupies one line.
471int x, y = 0;  // Bad: Multiple variable definitions must be separated on different lines. Each definition occupies one line.
472
473int pointX;
474int pointY;
475...
476pointX = 1; pointY = 2;  // Bad: Multiple variable assignment statements must be separated on different lines.
477```
478Exception: Multiple variables can be declared and initialized in the for loop header, if initialization statement (C++17), and structured binding statement (C++17). Multiple variable declarations in these statements have strong associations. Forcible division into multiple lines may cause problems such as scope inconsistency and separation of declaration from initialization.
479
480## Initialization
481Initialization is applicable to structs, unions, and arrays.
482
483### Rule 3.11.1 When an initialization list is wrapped, ensure that the line after the break is indented and aligned properly.
484If a structure or array initialization list is wrapped, the line after the break is indented with four spaces.
485Choose the wrap location and alignment style for best comprehension.
486
487```cpp
488const int rank[] = {
489    16, 16, 16, 16, 32, 32, 32, 32,
490    64, 64, 64, 64, 32, 32, 32, 32
491};
492```
493
494## Pointers and References
495### Rec 3.12.1 The pointer type `*` follows a variable name or type. There can be only one space to the side of it.
496Pointer naming: There can be only one space next to `*`.
497```cpp
498int* p = NULL;  // Good
499int *p = NULL;  // Good
500
501int*p = NULL;   // Bad
502int * p = NULL; // Bad
503```
504
505Exception: When a variable is modified by const or restrict, `*` cannot follow the variable or type.
506```cpp
507const char * const VERSION = "V100";
508```
509
510### Rec 3.12.2 The reference type `&` follows a variable name or type. There can be only one space to the side of it.
511Reference naming: There can be only one space around `&`.
512```cpp
513int i = 8;
514
515int& p = i;     // Good
516int &p = i;     // Good
517int*& rp = pi; // Good: The reference type `*&` follows the type.
518int *&rp = pi; // Good: The reference type `*&` follows the variable name.
519int* &rp = pi; // Good: The pointer type `*` follows the type and the reference type `&` follows the variable name.
520
521int & p = i;    // Bad
522int&p = i;      // Bad
523```
524
525## Compilation Preprocessing
526### Rule 3.13.1 Place a number sign (#) at the beginning of a line for compilation preprocessing. In nested compilation preprocessing, the number sign (#) can be indented.
527The number sign (#) must be placed at the beginning of a line for compilation preprocessing, even if the code is embedded in the function body.
528
529### Rule 3.13.2 Do not use macros.
530Macros do not obey scope, type system, and other rules, and may easily lead to issues. Avoid macro definitions wherever possible. If you must use macros, give them unique names.
531In C++, there are many ways to avoid using macros:
532- Use `const` or `enum` to define constants that are easy to understand.
533- Use namespaces to avoid name conflicts.
534- Use the `inline` function to avoid function call overhead.
535- Use the `template` function to handle multiple types.
536Macros can be used in scenarios such as header guards, conditional compilation, and logging.
537
538### Rule 3.13.3 Do not use macros to represent constants.
539Macros involve simple text replacement, which is completed during preprocessing. When an error occurs, the macro value is reported without the macro name. During tracing and debugging, the macro name is not displayed either. Besides, macros do not have type checking or scopes.
540
541### Rule 3.13.4 Do not use function-like macros.
542Before defining a function-like macro, consider whether it can be replaced with a function. If yes, you are advised to use a function for replacement.
543
544The disadvantages of the function-like macro are as follows:
545
546- Function-like macros have no type check, which is not as strict as the function call check.
547- If macro parameters are not evaluated during macro expansion, unexpected results may occur.
548- A macro has no independent scope.
549- There are high skill requirements on the proper use of macros (for example, the usage of `#` and wide use of parentheses), which reduces readability.
550- Extensions of some macros can only be implemented by specific compilers in specific scenarios, such as `statement expression` of `gcc`, reducing the portability.
551- After the macro is expanded during precompilation, it is invisible during subsequent compilation, linking, and debugging. Besides, macros that contain multiple lines are expanded into a line. Function-like macros are difficult to debug, set breakpoints, and locate in case of bugs.
552- Macros containing a large number of statements must be expanded at each call point. If there are many call points, the code will be expanded.
553
554Unlike macros, functions do not have these disadvantages. However, the biggest disadvantage of functions is low execution efficiency (increasing the overhead of function calls and the difficulty of compiler optimization).
555
556In light of this, you can use inline functions when necessary. Similar to macros, inline functions are expanded at the call point. The difference is that inline functions are expanded during compilation.
557
558Inline functions have the advantages of both functions and macros:
559- Strict type checking is performed for inline functions.
560- Parameters are evaluated only once for inline functions.
561- Inline functions are expanded in place and there is no overhead for function calls.
562- Inline functions are better optimized than standard functions.
563For performance-sensitive code, consider using inline functions instead of standard functions.
564
565Exceptions:
566
567In logging scenarios, only function-like macros can be used to keep information such as the file name (__FILE__) and line number (__LINE__) of the call point.
568
569## Whitespace
570### Rule 3.14.1 Ensure that horizontal spaces are used to highlight keywords and important information, and avoid unnecessary whitespace.
571Horizontal spaces are used to highlight keywords and important information. Spaces are not allowed at the end of each code line. The general rules are as follows:
572
573- Add spaces after keywords such as if, switch, case, do, while, and for.
574- Do not add spaces after the left parenthesis or before the right parenthesis.
575- For expressions enclosed by braces, either add a space on either side or avoid a space on either side.
576- Do not add spaces after any unary operator (& * + - ~ !).
577- Add a space to the left and right sides of each binary operator (= + -< > * /% | & ^ <= >= == !=).
578- Add spaces to the left and right sides of a ternary operator (? :).
579- Do not add spaces between a prefix or suffix increment (++) or decrement (--) operator and a variable.
580- Do not add spaces before or after a struct member operator (. ->).
581- Do not add spaces before commas. Add spaces after commas.
582- Do not add spaces between a template or type conversion operator (<>) and a type.
583- Do not add spaces before or after a domain operator (::).
584- Determine whether to add spaces before and after a colon (:) based on the actual situation.
585
586In normal cases:
587```cpp
588void Foo(int b) {  // Good: A space is added before the left brace.
589
590int i = 0;  // Good: During variable initialization, there should be spaces before and after =. Do not leave a space before the semicolon.
591
592int buf[BUF_SIZE] = {0}; // Good: Spaces are not added in braces.
593```
594
595Function definition and call:
596```cpp
597int result = Foo(arg1,arg2);
598                    ^    // Bad: A space should be added after the comma.
599
600int result = Foo( arg1, arg2 );
601                 ^          ^  // Bad: Spaces should not be added after the left parenthesis or before the right parenthesis.
602```
603
604Pointer and Address Operator
605```cpp
606x = *p;     // Good: There is no space between the operator * and the pointer p.
607p = &x;     // Good: There is no space between the operator & and the variable x.
608x = r.y;    // Good: When a member variable is accessed through the operator (.), no space is added.
609x = r->y;   // Good: When a member variable is accessed through the operator (->), no space is added.
610```
611
612Other Operators:
613```cpp
614x = 0;   // Good: There is a space before and after the assignment operator (=).
615x = -5;  // Good: There is no space between the minus sign (–) and the number.
616++x;     //Good: Do not add spaces between a prefix or suffix increment (++) or decrement (--) operator and a variable..
617x--;
618
619if (x && !y) // Good: There is a space before and after the Boolean operator. There is no space between the ! operator and the variable.
620v = w * x + y / z;  // Good: There is a space before and after the binary operator.
621v = w * (x + z);    // Good: There is no space before or after the expression in the parentheses.
622
623int a = (x < y) ? x : y;  // Good: Ternary operator. There is a space before and after ? and :
624```
625
626Loops and Conditional Statements:
627```cpp
628if (condition) {  // Good: There is a space between the if keyword and the left parenthesis, and no space before or after the conditional statement in the parentheses.
629    ...
630} else {           // Good: There is a space between the else keyword and the left brace.
631    ...
632}
633
634while (conditions) {}   // Good: There is a space between the while keyword and the left parenthesis. There is no space before or after the conditional statement in the parentheses.
635
636for (int i = 0; i < someRange; ++i) {  // Good: There is a space between the for keyword and the left parenthesis, and after the semicolon.
637    ...
638}
639
640switch (condition) {  // Good: There is a space after the switch keyword.
641    case 0:     // Good: There is no space between the case condition and the colon.
642        ...
643        break;
644    ...
645    default:
646        ...
647        break;
648}
649```
650
651Templates and Conversions
652```cpp
653// Angle brackets (< and >) are not adjacent to space. There is no space before < or between > and (.
654vector<string> x;
655y = static_cast<char*>(x);
656
657// There can be a space between the type and the pointer operator. Keep the spacing style consistent.
658vector<char *> x;
659```
660
661Scope Operators
662```cpp
663std::cout;    // Good: Namespace access. Do not leave spaces.
664
665int MyClass::GetValue() const {}  // Good: Do not leave spaces in the definition of member functions.
666```
667
668Colons
669```cpp
670// Scenarios when space is required
671
672// Good: // Add a space before or after the colon in a derived class definition.
673class Sub : public Base {
674
675};
676
677// Add a space before or after the colon in the initialization list of a constructor function.
678MyClass::MyClass(int var) : someVar_(var)
679{
680    DoSomething();
681}
682
683// Add a space before or after the colon in a bit-field.
684struct XX {
685    char a : 4;
686    char b : 5;
687    char c : 4;
688};
689```
690
691```cpp
692// Scenarios when space is not required
693
694// Good: // No space is added before or after the colon next to a class access permission (public or private).
695class MyClass {
696public:
697    MyClass(int var);
698private:
699    int someVar_;
700};
701
702// No space is added before or after the colon in a switch statement.
703switch (value)
704{
705    case 1:
706        DoSomething();
707        break;
708    default:
709        break;
710}
711```
712
713Note: Currently, all IDEs support automatic deletion of spaces at the end of a line. Please configure your IDE correctly.
714
715### Rec 3.14.1 Use blank lines only when necessary to keep code compact.
716
717There must be as few blank lines as possible so that more code can be displayed for easy reading. Recommendations:
718- Add blank lines according to the correlation between lines.
719- Consecutive blank lines are not allowed inside functions, type definitions, macros, and initialization expressions.
720- A maximum of **two** consecutive blank lines can be used.
721- Do not add blank lines on the first and last lines of a code block in braces. This recommendation is not applicable to code block in braces of a namespace.
722
723```cpp
724int Foo()
725{
726    ...
727}
728
729
730
731int bar() {// Bad: More than one blank lines are used between two function definitions.
732{
733    ...
734}
735
736
737if (...) {
738        // Bad: Do not add blank lines on the first and last lines of a code block.
739    ...
740        // Bad: Do not add blank lines on the first and last lines of a code block.
741}
742
743int Foo(...)
744{
745        // Bad: Do not add blank lines before the first statement in a function body.
746    ...
747}
748```
749
750## Classes
751### Rule 3.15.1 Class access specifier declarations are in the sequence: public, protected, private. Indent these specifiers to the same level as the class keyword.
752```cpp
753class MyClass : public BaseClass {
754public:      // Not indented.
755    MyClass();  // Indented with 4 spaces.
756    explicit MyClass(int var);
757    ~MyClass() {}
758
759    void SomeFunction();
760    void SomeFunctionThatDoesNothing()
761    {
762    }
763
764    void SetVar(int var) { someVar_ = var; }
765    int GetVar() const { return someVar_; }
766
767private:
768    bool SomeInternalFunction();
769
770    int someVar_;
771    int someOtherVar_;
772};
773```
774
775In each part, it is recommended that similar statements be put together and in the following order: Type (including typedef, using, nested structs and classes), Constant, Factory Function, Constructor, Assignment Operator, Destructor, Other Member Function, and Data Member
776
777
778### Rule 3.15.2 The constructor initialization list must be on the same line or wrapped and aligned with four spaces of indentation.
779```cpp
780// If all variables can be placed on the same line
781MyClass::MyClass(int var) : someVar_(var)
782{
783    DoSomething();
784}
785
786// If the variables cannot be placed on the same line
787// Wrapped at the colon and indented with four spaces
788MyClass::MyClass(int var)
789    : someVar_(var), someOtherVar_(var + 1)  // Good: Add a space after the comma.
790{
791    DoSomething();
792}
793
794//  If an initialization list needs to be placed in multiple lines, put each member on a separate line and align between lines.
795MyClass::MyClass(int var)
796    someVar(var),             // Four spaces of indentation.
797      someOtherVar_(var + 1)
798{
799    DoSomething();
800}
801```
802
803# 4 Comments
804Generally, clear architecture and good naming are recommended to improve code readability, and comments are provided only when necessary.
805
806Comments are used to help readers quickly understand code. Therefore, **comments should be provided for the sake of readers**.
807
808Comments must be concise, clear, and unambiguous, ensuring that information is complete and not redundant.
809
810**Comments are as important as code**.
811
812When writing a comment, you need to step into the reader's shoes and use comments to express what the reader really needs. Comments are used to express the function and intention of code, rather than repeating code.
813
814When modifying the code, ensure that the comments are consistent with the modified code. It is not polite to modify only code and keep the old comments, which will undermine the consistency between code and comments, and may confuse or even mislead readers.
815
816Comments should be made in English.
817
818## Comment Style
819
820In C++ code, both ` /* */` and ` // ` can be used for commenting.
821
822Comments can be classified into different types, such as file header comments, function header comments, and code comments. This is based on their purposes and positions.
823
824Comments of the same type must keep a consistent style.
825
826Note: Example code in this document uses comments in the `//` format only to better describe the rules and recommendations. This does not mean this comment format is better.
827
828## File Header Comments
829### Rule 4.2.1 File header comments must contain the copyright notice.
830
831/*
832 * Copyright (c) 2020 Huawei Device Co., Ltd.
833 * Licensed under the Apache License, Version 2.0 (the "License");
834 * you may not use this file except in compliance with the License.
835 * You may obtain a copy of the License at
836    *
837 * http://www.apache.org/licenses/LICENSE-2.0
838    *
839 * Unless required by applicable law or agreed to in writing, software
840 * distributed under the License is distributed on an "AS IS" BASIS,
841 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
842 * See the License for the specific language governing permissions and
843 * limitations under the License.
844    */
845
846## Function Header Comments
847### Rule 4.3.1 Write function header comments for public functions.
848Public functions are interfaces provided by classes for external systems. To use public functions, the caller must understand the functionalities, parameter value ranges, return values, and precautions of the functions.
849Write function header comments for the function value range, return value, and precautions, since they cannot be self-explained.
850
851### Rule 4.3.2 Function header comments with no content are forbidden.
852Not all functions need function header comments.
853
854For information that cannot be described by function signatures, add function header comments.
855
856Function header comments are placed above the function declaration or definition. Use one of the following styles:
857
858Use '//' to start the function header.
859
860```cpp
861// Single-line function header
862int Func1(void);
863
864// Multi-line function header
865// Second line
866int Func2(void);
867```
868
869Use `/*   */` to start the function header.
870```cpp
871/* Single-line function header */
872int Func1(void);
873
874/*
875 * Another single-line function header
876 */
877int Func2(void);
878
879/*
880 * Multi-line function header
881 * Second line
882 */
883int Func3(void);
884```
885Use function names to describe functions, and add function header comments if necessary.
886
887Do not write useless or redundant function headers. Do not write empty function headers with no content.
888
889The function header comment content will depend on the function and includes but is not limited to: a function description, return value, performance constraints, usage comments, memory conventions, algorithm implementation, reentering requirements.
890
891In the function interface declaration in the external header file, the function header comment should clearly describe important and useful information.
892
893Good example:
894
895```cpp
896/*
897 * The number of written bytes is returned. If -1 is returned, the write operation failed.
898 * Note that the memory buffer should be released by the caller.
899 */
900int WriteString(const char *buf, int len);
901```
902
903Bad example:
904```cpp
905/*
906 * Function name: WriteString
907 * Function: Write a character string.
908 * Parameters:
909 * Return value:
910 */
911int WriteString(const char *buf, int len);
912```
913Problems:
914
915- The 'Parameters' and 'Return value' have no content.
916- The function name is redundant.
917- The most import thing, that is, who needs to release the buffer, is not clearly stated.
918
919## Code Comments
920### Rule 4.4.1 Code comments are placed above or on the right of the corresponding code.
921### Rule 4.4.2 There must be a space between the comment character and the comment content. At least one space is required between the comment and code if the comment is placed to the right of code.
922Comments placed above code should be indented the same as that of the code.
923Use one of the following styles:
924Use "//".
925```cpp
926
927// Single-line comment
928DoSomething();
929
930// Multi-line comment
931// Second line
932DoSomething();
933```
934
935Use `/* */`.
936```cpp
937/* Single-line comment */
938DoSomething();
939
940/*
941 * Multi-line comment in another mode
942 * Second line
943 */
944DoSomething();
945```
946Leave at least one space between the code and the comment on the right. It is recommended that no more than four spaces be left.
947
948You can use the Tab key to indent 1–4 spaces.
949
950Select and use one of the following styles:
951
952```cpp
953int foo = 100;  // Comment on the right
954int bar = 200;  /* Comment on the right */
955```
956It is more appealing sometimes when the comment is placed on the right of code and the comments and code are aligned vertically.
957
958After the alignment, ensure that the comment is 1–4 spaces away from the widest line of code.
959Example:
960
961```cpp
962const int A_CONST = 100;         /* Related comments of the same type can be aligned vertically. */
963const int ANOTHER_CONST = 200;   /* Leave spaces after code to align comments vertically. */
964```
965When the comment on the right exceeds the line width, consider placing the comment above the code.
966
967### Rule 4.4.3 Delete unused code segments. Do not comment them out.
968Code that is commented out cannot be maintained. If you attempt to restore the code, it is very likely to introduce ignorable defects.
969
970The correct method is to delete unnecessary code directly. If necessary, consider porting or rewriting the code.
971
972Here, commenting out refers to the removal of code from compilation without actually deleting it. This is done by using /* */, //, #if 0, #ifdef NEVER_DEFINED, and so on.
973
974# 5 Header Files
975## Header File Responsibility
976A header file is an external interface of a module or file. The design of a header file shows most of the system design.
977
978The interface declaration for most functions is more suitable placed in the header file, but implementation (except inline functions) cannot be placed in the header file. Functions, macros, enumerations, and structure definitions that need to be used in .cpp files cannot be placed in the header file.
979
980The header responsibility should be simple. An overly complex header file will make dependencies complex and cause long compilation times.
981
982### Rec 5.1.1 Each .cpp file should have a .h file with the same name. It should be used to declare the classes and interfaces that need to be exposed externally.
983Generally, each .cpp file has a corresponding .h file. This .cpp file is used to store the function declarations, macro definitions, and class definitions that are to be exposed.
984
985If a .cpp file does not need to open any interface externally, it should not exist.
986
987Exception: __An entry point (for example, the file where the main function is located), unit tests, and dynamic libraries __
988
989Example:
990```cpp
991// Foo.h
992
993#ifndef FOO_H
994#define FOO_H
995
996class Foo {
997public:
998    Foo();
999    void Fun();
1000
1001private:
1002    int value_;
1003};
1004
1005#endif
1006```
1007
1008```cpp
1009// Foo.cpp
1010#include "Foo.h"
1011
1012namespace { // Good: The declaration of the internal function is placed in the header of the .cpp file, and has been limited to the unnamed namespace or static scope.
1013    void Bar()
1014    {
1015    }
1016}
1017
1018...
1019
1020void Foo::Fun()
1021{
1022    Bar();
1023}
1024```
1025
1026## Header File Dependency
1027### Rule 5.2.1 Header file cyclic dependency is forbidden.
1028An example of cyclic dependency (also known as circular dependency) is: a.h contains b.h, b.h contains c.h, and c.h contains a.h. If any of these header files is modified, all code containing a.h, b.h, and c.h needs to be recompiled.
1029
1030For a unidirectional dependency, for example if: a.h contains b.h, b.h contains c.h, and c.h does not contain any header file, modifying a.h does not mean that we need to recompile the source code for b.h or c.h.
1031
1032The cyclic dependency of header files reflects an obviously unreasonable architecture design, which can be avoided through optimization.
1033
1034
1035### Rule 5.2.2 Header files should have #define guards to prevent multiple inclusion.
1036To prevent header files from being included multiple times, all header files should be protected by #define. Do not use #pragma once.
1037
1038When defining a protection character, comply with the following rules:
1039
10401) The protection character uses a unique name.
1041
10422) Do not place code or comments (except for file header comments) before or after the protected part.
1043
1044Example: Assume that the timer.h file of the timer module is in the timer/include/timer.h directory. Perform the following operations to safeguard the timer.h file:
1045
1046```cpp
1047#ifndef TIMER_INCLUDE_TIMER_H
1048#define TIMER_INCLUDE_TIMER_H
1049...
1050#endif
1051```
1052
1053### Rule 5.2.3 It is prohibited to reference external function interfaces and variables in extern declaration mode.
1054Interfaces provided by other modules or files can be used only by including header files.
1055
1056Using external function interfaces and variables in extern declaration mode may cause inconsistency between declarations and definitions when external interfaces are changed.
1057
1058In addition, this kind of implicit dependency may cause architecture corruption.
1059
1060Cases that do not comply with specifications:
1061
1062// a.cpp content
1063```cpp
1064extern int Fun();   // Bad: Use external functions in extern mode.
1065
1066void Bar()
1067{
1068    int i = Fun();
1069    ...
1070}
1071```
1072
1073// b.cpp content
1074```cpp
1075int Fun()
1076{
1077    // Do something
1078}
1079```
1080Should be changed to:
1081
1082// a.cpp content
1083```cpp
1084#include "b.h"   // Good: Use the interface provided by other .cpp by including its corresponding header file.
1085
1086void Bar()
1087{
1088    int i = Fun();
1089    ...
1090}
1091```
1092
1093// b.h content
1094```cpp
1095int Fun();
1096```
1097
1098// b.cpp content
1099```cpp
1100int Fun()
1101{
1102    // Do something
1103}
1104```
1105In some scenarios, if internal functions need to be referenced with no intrusion to the code, the extern declaration mode can be used.
1106
1107Example:
1108
1109When performing unit testing on an internal function, you can use the extern declaration to reference the tested function.
1110
1111When a function needs to be stubbed or patched, the function can be declared using extern.
1112
1113### Rule 5.2.4 Do not include header files in extern "C".
1114If a header file is included in extern "C", extern "C" may be nested. Some compilers restrict the nesting of extern "C". If there are too many nested layers, compilation errors may occur.
1115
1116When C and C++ programmings are used together and if extern "C" includes a header file, the original intent behind the header file may be hindered. For example, when the link specifications are modified incorrectly.
1117
1118For example, assume that there are two header files a.h and b.h.
1119
1120// a.h content
1121```cpp
1122...
1123#ifdef __cplusplus
1124void Foo(int);
1125#define A(value) Foo(value)
1126#else
1127void A(int)
1128#endif
1129```
1130// b.h content
1131```cpp
1132...
1133#ifdef __cplusplus
1134extern "C" {
1135#endif
1136
1137#include "a.h"
1138void B();
1139
1140#ifdef __cplusplus
1141}
1142#endif
1143```
1144
1145Using the C++ preprocessor to expand b.h, the following information is displayed:
1146```cpp
1147extern "C" {
1148    void Foo(int);
1149    void B();
1150}
1151```
1152
1153According to the author of a.h, the function Foo is a C++ free function following the "C++" link specification.
1154However, because `#include "a.h"` is placed inside `extern "C"` in b.h, the link specification of function Foo is changed incorrectly.
1155
1156Exceptions:
1157In the C++ compilation environment, if you want to reference the header file of pure C, the C header files should not contain `extern "C"`. The non-intrusive approach is to include the C header file in `extern "C"`.
1158
1159### Rec 5.2.1 Use `#include` instead of a forward declaration to include header files.
1160A forward declaration is for the declaration of classes, functions, and templates and is not meant for its definition.
1161
1162- Advantages:
1163  1. Forward declarations can save compilation time. Redundant `#include `statements force the compiler to expand more files and process more input.
1164  2. Forward declarations can save unnecessary recompilation time. The use of #include will force your code to be recompiled multiple times due to unrelated changes in header files.
1165- Disadvantages:
1166  1. Forward declarations hide dependency relationship. When a header file is modified, user code will skip the necessary recompilation process.
1167  2. A forward declaration may be broken by subsequent changes to the library. Forward declarations of functions and templates sometimes prevent header file developers from changing APIs. For example, widening a formal parameter type, adding a template parameter with a default value, and so on.
1168  3. Forward declaration of symbols from the namespace `std::` is seen as undefined behavior (as specified in the C++ 11 standard specification).
1169  4. Forward declaration of multiple symbols from a header file can be more verbose than simply including (#include) the header.
1170  5. Structuring code only for forward declaration (for example, using pointer members instead of object members) can make the code more complex and slower.
1171  6. It is difficult to determine whether a forward declaration or `#include` is needed. In some scenarios, replacing `#include` with a forward declaration may cause unexpected results.
1172
1173Therefore, we should avoid using forward declarations as much as possible. Instead, we use the #include statement to include a header file and ensure dependency.
1174
1175# 6 Scopes
1176
1177## Namespaces
1178
1179### Rec 6.1.1 For code that does not need to be exported from the .cpp file, you are advised to use an unnamed namespace for encapsulation or use static to modify the variables, constants, or functions that need hiding.
1180In the C++ 2003 standard, using static to modify the external availability of functions and variables was marked as deprecated. Therefore, unnamed namespaces are the recommended method.
1181
1182Main Reasons:
11831. There are too many meanings for static in C++: static function member variable, static member function, static global variable, and static function local variable. Each of them has special processing.
11842. Static can only be used to define variables, constants, and functions that are not referenced outside the current .cpp file, while namespaces can also be used to encapsulate types.
11853. Use a namespace to control the scope instead of using both static and namespaces.
11864. Unnamed namespaces can be used to instantiate templates rather than functions modified by the static keyword.
1187
1188Do not use unnamed namespaces or static in header files.
1189
1190```cpp
1191// Foo.cpp
1192
1193namespace {
1194    const int MAX_COUNT = 20;
1195    void InternalFun(){};
1196}
1197
1198void Foo::Fun()
1199{
1200    int i = MAX_COUNT;
1201
1202    InternalFun();
1203}
1204
1205```
1206
1207### Rule 6.1.1 Do not use "using" to import namespace in a header file or before #include statements.
1208Note: Using "using" to import namespace will affect any subsequent code and may cause symbol conflicts.
1209Example:
1210
1211```cpp
1212// Header file a.h
1213namespace NamespaceA {
1214    int Fun(int);
1215}
1216```
1217
1218```cpp
1219// Header file b.h
1220namespace NamespaceB {
1221    int Fun(int);
1222}
1223
1224using namespace NamespaceB;
1225
1226void G()
1227{
1228    Fun(1);
1229}
1230```
1231
1232```cpp
1233// Source code a.cpp
1234#include "a.h"
1235using namespace NamespaceA;
1236#include "b.h"
1237
1238void main()
1239{
1240    G(); // "using namespace NamespaceA" before #include "b.h", will cause conflicts when calling NamespaceA::Fun and NamespaceB::Fun.
1241}
1242```
1243
1244Using "using" to import a symbol or define an alias in a header file is allowed in customized namespaces of modules, but is prohibited in the global namespace.
1245```cpp
1246// foo.h
1247
1248#include <fancy/string>
1249using fancy::string;  // Bad: It is prohibited to import symbols to the global namespace.
1250
1251namespace Foo {
1252    using fancy::string;  // Good: Symbols can be imported in customized namespaces of modules.
1253    using MyVector = fancy::vector;  // Good: In C++11, aliases can be defined in customized namespaces.
1254}
1255```
1256
1257
1258## Global Functions and Static Member Functions
1259
1260### Rec 6.2.1 Use namespaces to manage global functions. If global functions are closely tied to a class, you can use static member functions.
1261Note: Placing non-member functions in a namespace avoids polluting the global scope. Do not use "class + static member function" to simply manage global functions. If a global function is closely tied to a class, it can be used as a static member function of the class.
1262
1263If you need to define some global functions for a .cpp file, use unnamed namespaces for management.
1264```cpp
1265namespace MyNamespace {
1266    int Add(int a, int b);
1267}
1268
1269class File {
1270public:
1271    static File CreateTempFile(const std::string& fileName);
1272};
1273```
1274
1275## Global Constants and Static Member Constants
1276
1277### Rec 6.3.1 Use namespaces to manage global constants. If global constants are closely tied to a class, you can use static member constants.
1278Note: Placing global constants in a namespace avoids polluting the global scope. Do not use "class + static member constant" to simply manage global constants. If a global constant is closely tied to a class, it can be used as a static member constant of the class.
1279
1280If you need to define some global constants only for a .cpp file, use unnamed namespaces for management.
1281```cpp
1282namespace MyNamespace {
1283    const int MAX_SIZE = 100;
1284}
1285
1286class File {
1287public:
1288    static const std::string SEPARATOR;
1289};
1290```
1291
1292## Global Variables
1293
1294### Rec 6.4.1 Do not use global variables. Use the singleton pattern instead.
1295Note: Global variables can be modified and read, which results in data coupling between production code and the global variables.
1296```cpp
1297int g_counter = 0;
1298
1299// a.cpp
1300g_counter++;
1301
1302// b.cpp
1303g_counter++;
1304
1305// c.cpp
1306cout << g_counter << endl;
1307```
1308
1309Singleton
1310```cpp
1311class Counter {
1312public:
1313    static Counter& GetInstance()
1314    {
1315        static Counter counter;
1316        return counter;
1317    }  // Simple example of a singleton implementation
1318
1319    void Increase()
1320    {
1321        value_++;
1322    }
1323
1324    void Print() const
1325    {
1326        std::cout << value_ << std::endl;
1327    }
1328
1329private:
1330    Counter() : value_(0) {}
1331
1332private:
1333    int value_;
1334};
1335
1336// a.cpp
1337Counter::GetInstance().Increase();
1338
1339// b.cpp
1340Counter::GetInstance().Increase();
1341
1342// c.cpp
1343Counter::GetInstance().Print();
1344```
1345
1346After the singleton is implemented, there is a unique global instance, which can functions as a global variable. However, the singleton provides better encapsulation.
1347
1348Exception: In some cases, the scope of a global variable is contained inside a module. Multiple instances of the same global variable may exist, and each module holds one copy. In this case, a singleton cannot be used as it is limited to one instance.
1349
1350# 7 Classes
1351
1352## Constructors, Copy/Move Constructors, Copy/Move Assignment Operators, and Destructors
1353Constructors, copy/move constructors, copy/move assignment operators, and destructors provide lifetime management methods for objects.
1354- Constructor: `X()`
1355- Copy constructor: `X(const X&)`
1356- Copy assignment operator: `operator=(const X&)`
1357- Move constructor: `X (X&&)`         *Provided in versions later than C++ 11*.
1358- Move assignment operator: `operator=(X&&)`       *Provided in versions later than C++ 11*.
1359- Destructor: `~X()`
1360
1361### Rule 7.1.1 The member variables of a class must be initialized explicitly.
1362Note: If a class has members but no constructor and a default constructor is defined, the compiler will automatically generate a constructor, but it will not initialize member variables. The content of each object is uncertain.
1363
1364Exceptions:
1365- If the member variables in a class have a default constructor, explicit initialization is not required.
1366
1367Example: The following code has no constructor, and private data members cannot be initialized:
1368```cpp
1369class Message {
1370public:
1371    void ProcessOutMsg()
1372    {
1373        //...
1374    }
1375
1376private:
1377    unsigned int msgID_;
1378    unsigned int msgLength_;
1379    unsigned char* msgBuffer_;
1380    std::string someIdentifier_;
1381};
1382
1383Message message;   // The message member is not initialized.
1384message.ProcessOutMsg();   // Potential risks exist in subsequent use.
1385
1386// Therefore, it is necessary to define a default constructor as follows:
1387class Message {
1388public:
1389    Message() : msgID_(0), msgLength_(0), msgBuffer_(NULL)
1390    {
1391    }
1392
1393    void ProcessOutMsg()
1394    {
1395        // ...
1396    }
1397
1398private:
1399    unsigned int msgID_;
1400    unsigned int msgLength_;
1401    unsigned char* msgBuffer_;
1402    std::string someIdentifier; // The member variable has a default constructor. Therefore, explicit initialization is not required.
1403};
1404```
1405
1406### Rec 7.1.1 Initialization during declaration (C++ 11) and initialization using the constructor initialization list are preferred for member variables.
1407Note: Initialization during declaration (C++11) is preferred because initialized values of member variables can be easily understood. If initialized values of certain member variables are relevant to constructors, or C++ 11 is not supported, the constructor initialization list is used preferentially to initialize these member variables. Compared with the assignment statements in constructors, code of the constructor initialization list is simpler and has higher performance, and can be used to initialize constant and reference members.
1408
1409```cpp
1410class Message {
1411public:
1412    Message() : msgLength(0) {  // Good: The constructor initialization list is preferred.
1413    {
1414        msgBuffer = NULL;     // Bad: Values cannot be assigned in constructors.
1415    }
1416
1417private:
1418    unsigned int msgID{0};  // Good: Used in C++11.
1419    unsigned int msgLength_;
1420    unsigned char* msgBuffer_;
1421};
1422```
1423
1424### Rule 7.1.2 Declare single-parameter constructors as explicit to prevent implicit conversion.
1425Note: If a single-parameter constructor is not declared as explicit, it will become an implicit conversion function.
1426Example:
1427
1428```cpp
1429class Foo {
1430public:
1431    explicit Foo(const string& name): name_(name)
1432    {
1433    }
1434private:
1435    string name_;
1436};
1437
1438
1439void ProcessFoo(const Foo& foo){}
1440
1441int main(void)
1442{
1443    std::string test = "test";
1444    ProcessFoo(test);  // Compiling failed.
1445    return 0;
1446}
1447```
1448
1449The preceding code fails to be compiled because the parameter required by `ProcessFoo` is of the Foo type, which mismatch with the input string type.
1450
1451If the explicit keyword of the Foo constructor is removed, implicit conversion is triggered and a temporary Foo object is generated when `ProcessFoo` is called with the string parameter. Usually, this implicit conversion is confusing and bugs are apt to be hidden, due to unexpected type conversion. Therefore, single-parameter constructors require explicit declaration.
1452
1453### Rule 7.1.3 If copy/move constructors and copy/move assignment operators are not needed, clearly prohibit them.
1454Note: If users do not define it, the compiler will generate copy constructors and copy assignment operators, move constructors and move assignment operators (move semantic functions will be available in versions later than C++ 11).
1455If we do not use copy constructors or copy assignment operators, explicitly delete them.
1456
14571. Set copy constructors or copy assignment operators to private and do not implement them.
1458```cpp
1459class Foo {
1460private:
1461    Foo(const Foo&);
1462    Foo& operator=(const Foo&);
1463};
1464```
14652. Use delete provided by C++ 11. For details, see Rule 10.1.3 in chapter 10 Modern C++ Features.
1466
1467
14683. You are advised to inherit **NoCopyable** and **NoMovable**. Do not use macros such as **DISALLOW_COPY_AND_MOVE**, **DISALLOW_COPY**, and **DISALLOW_MOVE**.
1469```cpp
1470class Foo : public NoCopyable, public NoMovable {
1471};
1472```
1473Implementation of NoCopyable and NoMovable:
1474```cpp
1475class NoCopyable {
1476public:
1477    NoCopyable() = default;
1478    NoCopyable(const NoCopyable&) = delete;
1479    NoCopyable& operator = (NoCopyable&) = delete;
1480};
1481
1482class NoMovable {
1483public:
1484    NoMovable() = default;
1485    NoMovable(NoMovable&&) noexcept = delete;
1486    NoMovable& operator = (NoMovable&&) noexcept = delete;
1487};
1488```
1489
1490### Rule 7.1.4 Copy constructors and copy assignment operators should be implemented or forbidden together.
1491Both copy constructors and copy assignment operators provide copy semantics. They should be implemented or hidden together.
1492
1493```cpp
1494// The copy constructor and the copy assignment operator are implemented together.
1495class Foo {
1496public:
1497    ...
1498    Foo(const Foo&);
1499    Foo& operator=(const Foo&);
1500    ...
1501};
1502
1503// The copy constructor and the copy assignment operator are both set to default, as supported by C++ 11.
1504class Foo {
1505public:
1506    Foo(const Foo&) = default;
1507    Foo& operator=(const Foo&) = default;
1508};
1509
1510// The copy constructor and the copy assignment operator are hidden together. You should use the delete keyword if C++11 features are available.
1511class Foo {
1512private:
1513    Foo(const Foo&);
1514    Foo& operator=(const Foo&);
1515};
1516```
1517
1518### Rule 7.1.5 Move constructors and move assignment operators should be implemented or hidden together.
1519The move operation is added in C++ 11. If a class is required to support the move operation, move constructors and move assignment operators need to be implemented.
1520
1521Both move constructors and move assignment operators provide move semantics. They should be implemented or hidden together.
1522```cpp
1523// The copy constructor and the copy assignment operator are implemented together.
1524class Foo {
1525public:
1526    ...
1527    Foo(Foo&&);
1528    Foo& operator=(Foo&&);
1529    ...
1530};
1531
1532// The copy constructor and the copy assignment operator are both set to default, as supported by C++ 11.
1533class Foo {
1534public:
1535    Foo(Foo&&) = default;
1536    Foo& operator=(Foo&&) = default;
1537};
1538
1539// The copy constructor and the copy assignment operator are hidden together. You should use the delete keyword if C++11 features are available.
1540class Foo {
1541public:
1542    Foo(Foo&&) = delete;
1543    Foo& operator=(Foo&&) = delete;
1544};
1545```
1546
1547### Rule 7.1.6 It is prohibited to call virtual functions in constructors and destructors.
1548Note: Calling a virtual function of the current object in a constructor or destructor will cause behaviors of non-polymorphism.
1549
1550In C++, a base class constructs only one complete object at a time.
1551
1552Example: Base indicates the base class, and Sub indicates the derived class.
1553```cpp
1554class Base {
1555public:
1556    Base();
1557    virtual void Log() = 0;    // Different derived classes call different log files.
1558};
1559
1560Base::Base()         // Base class constructor
1561{
1562    Log();           // Call the virtual function log.
1563}
1564
1565class Sub : public Base {
1566public:
1567    virtual void Log();
1568};
1569```
1570
1571When running the following statement:
1572
1573`Sub sub;`
1574
1575The constructor of the derived class is executed first. However, the constructor of the base class is called first. Because the constructor of the base class calls the virtual function log, the log is in the base class version. The derived class is constructed only after the base class is constructed. As a result, behaviors of non-polymorphism are caused.
1576
1577This also applies to destructors.
1578
1579### Rule 7.1.7 The copy constructors, copy assignment operators, move constructors, and move assignment operators in polymorphic base classes must be non-public or delete functions.
1580Slicing occurs if the value of a derived class object is directly assigned to a base class object. In this case, only the base class part is copied or moved, which undermines polymorphism.
1581
1582[Counterexample]
1583
1584In the following code example, the copy constructor and copy assignment operator are not defined in the base class. The compiler automatically generates two special member functions.
1585
1586If the value of a derived class object is assigned to the base class object, slicing occurs. The copy constructor and copy assignment operator can be declared as **deleted** so that the compiler can check such assignment behavior.
1587
1588```cpp
1589class Base {
1590public:
1591    Base() = default;
1592    virtual ~Base() = default;
1593    ...
1594    virtual void Fun() { std::cout << "Base" << std::endl;}
1595};
1596
1597class Derived : public Base {
1598    ...
1599    void Fun() override { std::cout << "Derived" << std::endl; }
1600};
1601
1602void Foo(const Base &base)
1603{
1604    Base other = base; // Bad: Slicing occurs
1605    other.Fun(); // The Fun() function of the base class is called.
1606}
1607```
1608```cpp
1609Derived d;
1610Foo(d); // A derived class object is passed.
1611```
1612Set copy constructors or copy assignment operators to **private** and do not implement them.
1613
1614## Inheritance
1615
1616### Rule 7.2.1 Declare destructors of a base class as virtual, and declare the class that is not to be inherited as final.
1617Note: Destructors of the derived class can be called during polymorphism invocation only when destructors of the base class are virtual.
1618
1619Example: There will be memory leak if destructors of the base class are not declared as virtual.
1620```cpp
1621class Base {
1622public:
1623    virtual std::string getVersion() = 0;
1624
1625    ~Base()
1626    {
1627        std::cout << "~Base" << std::endl;
1628    }
1629};
1630```
1631
1632```cpp
1633class Sub : public Base {
1634public:
1635    Sub() : numbers_(NULL)
1636    {
1637    }
1638
1639    ~Sub()
1640    {
1641        delete[] numbers_;
1642        std::cout << "~Sub" << std::endl;
1643    }
1644
1645    int Init()
1646    {
1647        const size_t numberCount = 100;
1648        numbers_ = new (std::nothrow) int[numberCount];
1649        if (numbers_ == NULL) {
1650            return -1;
1651        }
1652
1653        ...
1654    }
1655
1656    std::string getVersion()
1657    {
1658        return std::string("hello!");
1659    }
1660private:
1661    int* numbers_;
1662};
1663```
1664
1665```cpp
1666int main(int argc, char* args[])
1667{
1668    Base* b = new Sub();
1669
1670    delete b;
1671    return 0;
1672}
1673```
1674Because destructors of the base class are not declared as virtual, only destructors of the base class are called when an object is destroyed. Destructors of the derived class Sub are not called. As a result, a memory leak occurs.
1675
1676Exceptions:
1677
1678For classes such as **NoCopyable** and **NoMovable** that have no behavior and are used only as identifiers, you do not need to define them as final.
1679
1680### Rule 7.2.2 Do not use default parameter values for virtual functions.
1681Note: In C++, virtual functions are dynamically bound, but the default parameters of functions are statically bound during compilation. This means that the function you finally execute is a virtual function that is defined in the derived class but uses the default parameter value in the base class. To avoid confusion and other problems caused by inconsistent default parameter declarations during overriding of virtual functions, it is prohibited to declare default parameter values for all virtual functions.
1682
1683Example: The default value of parameter "text" of the virtual function "Display" is determined at compilation time instead of runtime, which does not fit with polymorphism.
1684
1685```cpp
1686class Base {
1687public:
1688    virtual void Display(const std::string& text = "Base!")
1689    {
1690        std::cout << text << std::endl;
1691    }
1692
1693    virtual ~Base(){}
1694};
1695
1696class Sub : public Base {
1697public:
1698    virtual void Display(const std::string& text  = "Sub!")
1699    {
1700        std::cout << text << std::endl;
1701    }
1702
1703    virtual ~Sub(){}
1704};
1705
1706int main()
1707{
1708    Base* base = new Sub();
1709    Sub* sub = new Sub();
1710
1711    ...
1712
1713    base->Display();  // The program output is as follows: Base! The expected output is as follows: Sub!
1714    sub->Display();   // The program output is as follows: Sub!
1715
1716    delete base;
1717    delete sub;
1718    return 0;
1719};
1720```
1721
1722### Rule 7.2.3 Do not redefine inherited non-virtual functions.
1723Note: Non-virtual functions cannot be dynamically bound (only virtual functions can be dynamically bound). You can obtain the correct result by operating on the pointer of the base class.
1724
1725Example:
1726```cpp
1727class Base {
1728public:
1729    void Fun();
1730};
1731
1732class Sub : public Base {
1733public:
1734    void Fun();
1735};
1736
1737Sub* sub = new Sub();
1738Base* base = sub;
1739
1740sub->Fun();    // Call Fun of the derived class.
1741base->Fun();   // Call Fun of the base class.
1742//...
1743
1744```
1745
1746## Multiple Inheritance
1747In the actual development process, multiple inheritance is seldom used because the following typical problems may occur:
17481. Data duplication and name ambiguity caused by "diamond" inheritance. C++ introduces virtual inheritance to solve these problems.
17492. In addition to "diamond" inheritance, names of multiple base classes may also conflict with each other, resulting in name ambiguity.
17503. If a derived class needs to be extended or needs to override methods of multiple base classes, the responsibilities of the derived classes are unclear and semantics are muddled.
17514. Compared with delegation, inheritance is seen as white box reuse, that is, a derived class can access the protected members of the base class, which leads to more coupling. Multiple inheritance, due to the coupling of multiple base classes, leads to even more coupling.
1752
1753Multiple inheritance has the following advantages:
1754Multiple inheritance provides a simpler method for assembling and reusing multiple interfaces or classes.
1755
1756Therefore, multiple inheritance can be used only in the following cases:
1757
1758### Rec 7.3.1 Use multi-inheritance to implement interface separation and multi-role combination.
1759If a class requires multiple interfaces, combine multiple separated interfaces by using multiple inheritance. This is similar to the Traits mixin of the Scala language.
1760
1761```cpp
1762class Role1 {};
1763class Role2 {};
1764class Role3 {};
1765
1766class Object1 : public Role1, public Role2 {
1767    // ...
1768};
1769
1770class Object2 : public Role2, public Role3 {
1771    // ...
1772};
1773
1774```
1775
1776The C++ standard library has a similar implementation example:
1777```cpp
1778class basic_istream {};
1779class basic_ostream {};
1780
1781class basic_iostream : public basic_istream, public basic_ostream {
1782
1783};
1784```
1785
1786## Overloading
1787
1788Overload operators should be used when there are sufficient reasons, and they do not change the original perception of the operators. For example, do not use the plus sign (+) to perform subtraction.
1789Operator overloading can make code more intuitive but has some disadvantages:
1790- It is often mistaken that the operation is as fast as a built-in operator, which has no performance degradation.
1791- There is no naming to aid debugging. It is more convenient to search by function name than by operator.
1792- Overloading operators can cause confusion if behavior definitions are not intuitive (for example, if the "+" operator is used for subtraction).
1793- The implicit conversion caused by the overloading of assignment operators may lead to entrenched bugs. Functions such as Equals () and CopyFrom () can be defined to replace the = and == operators.
1794
1795# 8 Functions
1796## Function Design
1797### Rule 8.1.1 Avoid long functions and ensure that each function contains no more than 50 lines (non-null and non-comment).
1798A function should be displayed on one screen (no longer than 50 lines). It should do only one thing, and do it well.
1799
1800Long functions often mean that the functions are too complex to implement in more than one function, or overly detailed but not further abstracted.
1801
1802Exception: Some algorithms may be longer than 50 lines due to algorithm convergence and functional comprehensiveness.
1803
1804Even if a long function works very well now, once someone modifies it, new problems may occur. It might even cause bugs that are difficult to find.
1805
1806It is recommended that you split a long function into several functions that are simpler and easier to manage, facilitating comprehension and modification.
1807
1808## Inline Functions
1809
1810###  Rec 8.2.1 An inline function cannot exceed 10 lines.
1811**Note**: An inline function has the same characteristics of a normal function. The difference between an inline function and a normal function lies in the processing of function calls. When a general function is called, the program execution right is transferred to the called function, and then returned to the function that calls it. When an inline function is called, the invocation expression is replaced with an inline function body.
1812
1813Inline functions are only suitable for small functions with only 1-10 lines. For a large function that contains many statements, the function call and return overheads are relatively trivial and do not need the help of an inline function. Most compilers may abandon the inline mode and use the common method to call the function.
1814
1815If an inline function contains complex control structures, such as loop, branch (switch), and try-catch statements, the compiler may regard the function as a common function.
1816**Virtual functions and recursive functions cannot be used as inline functions**.
1817
1818## Function Parameters
1819
1820### Rec 8.3.1 Use a reference instead of a pointer for function parameters.
1821
1822**Note**: A reference is more secure than a pointer because it is not empty and does not point to other targets. Using a reference stops the need to check for illegal null pointers.
1823
1824If a product is being developed for an older platform, the processing used by the old platform is preferred.
1825Use const to avoid parameter modification, so that readers can clearly know that a parameter is not going to be modified. This greatly enhances code readability.
1826
1827Exception: When the input parameter is an array with an unknown compile-time length, you can use a pointer instead of a reference.
1828
1829### Rec 8.3.2 Use strongly typed parameters. Do not use void*.
1830While different languages have their own views on strong typing and weak typing, it is generally believed that C and C++ are strongly typed languages. Since we use such a strongly typed language, we should keep to this style.
1831
1832An advantage of this is the compiler can find type mismatch problems at the compilation stage.
1833
1834Using strong typing helps the compiler find more errors for us. Pay attention to the usage of the FooListAddNode function in the following code:
1835```cpp
1836struct FooNode {
1837    struct List link;
1838    int foo;
1839};
1840
1841struct BarNode {
1842    struct List link;
1843    int bar;
1844}
1845
1846void FooListAddNode(void *node) // Bad: Here, the void * type is used to transfer parameters.
1847{
1848    FooNode *foo = (FooNode *)node;
1849    ListAppend(&g_FooList, &foo->link);
1850}
1851
1852void MakeTheList()
1853{
1854    FooNode *foo = NULL;
1855    BarNode *bar = NULL;
1856    ...
1857
1858    FooListAddNode(bar);        // Wrong: In this example, the foo parameter was supposed to be transferred, but the bar parameter is accidentally transferred instead. However, no error is reported.
1859}
1860```
1861
18621. You can use a template function to change the parameter type.
18632. A base class pointer can be used to implement this according to polymorphism.
1864
1865### Rec 8.3.3 A function can have a maximum of five parameters.
1866If a function has too many parameters, it is apt to be affected by external changes, and therefore maintenance is affected. Too many function parameters will also increase the testing workload.
1867
1868If a function has more than five parameters, you can:
1869- Split the function.
1870- Combine related parameters into a struct.
1871
1872# 9 Other C++ Features
1873
1874## Constants and Initialization
1875
1876Unchanged values are easier to understand, trace, and analyze. Therefore, use constants instead of variables as much as possible. When defining values, use const as a default.
1877
1878### Rule 9.1.1 Do not use macros to replace constants.
1879
1880**Note**: Macros are a simple text replacement that is completed in the preprocessing phase. When an error is reported, the corresponding value is reported. During tracing and debugging, the value is also displayed instead of the macro name. A macro does not support type checking and is insecure. A macro has no scope.
1881
1882```cpp
1883#define MAX_MSISDN_LEN 20    // Bad
1884
1885// Use const in C++.
1886const int MAX_MSISDN_LEN = 20; // Good
1887
1888// In versions later than C++ 11, constexpr can be used.
1889constexpr int MAX_MSISDN_LEN = 20;
1890```
1891
1892###  Rec 9.1.1 A group of related integer constants must be defined as an enumeration.
1893
1894**Note**: Enumerations are more secure than `#define` or `const int`. The compiler checks whether a parameter value is within the enumerated value range to avoid errors.
1895
1896```cpp
1897// Good example:
1898enum Week {
1899    SUNDAY,
1900    MONDAY,
1901    TUESDAY,
1902    WEDNESDAY,
1903    THURSDAY,
1904    FRIDAY,
1905    SATURDAY
1906};
1907
1908enum Color {
1909    RED,
1910    BLACK,
1911    BLUE
1912};
1913
1914void ColorizeCalendar(Week today, Color color);
1915
1916ColorizeCalendar(BLUE, SUNDAY); // Compilation error. The parameter type is incorrect.
1917
1918// Bad example:
1919const int SUNDAY = 0;
1920const int MONDAY = 1;
1921
1922const int BLACK  = 0;
1923const int BLUE   = 1;
1924
1925bool ColorizeCalendar(int today, int color);
1926ColorizeCalendar(BLUE, SUNDAY); // No error is reported.
1927```
1928
1929When an enumeration value needs to correspond to a specific value, explicit value assignment is required during declaration. Otherwise, do not assign explicit values. This will prevent repeated assignment and reduce the maintenance workload (when adding and deleting members).
1930
1931```cpp
1932// Good example: Device ID defined in the S protocol. It is used to identify a device type.
1933enum DeviceType {
1934    DEV_UNKNOWN = -1,
1935    DEV_DSMP = 0,
1936    DEV_ISMG = 1,
1937    DEV_WAPPORTAL = 2
1938};
1939```
1940
1941Do not assign explicit values when enumeration is used internally, and only for classification.
1942
1943```cpp
1944// Good example: Enumeration definition is used to identify session status in a program.
1945enum SessionState {
1946    INIT,
1947    CLOSED,
1948    WAITING_FOR_RESPONSE
1949};
1950```
1951
1952Try to avoid repeating enumeration values. If it is required, use the already defined enumeration values instead.
1953
1954```cpp
1955enum RTCPType {
1956    RTCP_SR = 200,
1957    RTCP_MIN_TYPE = RTCP_SR,
1958    RTCP_RR    = 201,
1959    RTCP_SDES  = 202,
1960    RTCP_BYE   = 203,
1961    RTCP_APP   = 204,
1962    RTCP_RTPFB = 205,
1963    RTCP_PSFB  = 206,
1964    RTCP_XR  = 207,
1965    RTCP_RSI = 208,
1966    RTCP_PUBPORTS = 209,
1967    RTCP_MAX_TYPE = RTCP_PUBPORTS
1968};
1969```
1970
1971### Rule 9.1.2 Magic numbers cannot be used.
1972So-called magic numbers are numbers that are unintelligible and difficult to understand.
1973
1974Some numbers can be understood based on context.
1975
1976For example, the number 12 varies in different contexts.
1977
1978type = 12; is not intelligible (and a magic number), but `month = year * 12`; can be understood, so we wouldn't really class this as a magic number.
1979
1980The number 0 is often seen as a magic number. For example, `status = 0`; cannot truly express any status information.
1981
1982Solution:
1983
1984Comments can be added for numbers that are used locally.
1985
1986For the numbers that are used multiple times, you must define them as constants and give them descriptive names.
1987
1988The following cases are forbidden:
1989
1990No symbol is used to explain the meaning of a number, for example, ` const int ZERO = 0`.
1991The symbol name limits the value. For example, for example, `const int XX_TIMER_INTERVAL_300MS = 300`. Use `XX_TIMER_INTERVAL_MS` instead.
1992
1993### Rule 9.1.3 Ensure that a constant has only one responsibility.
1994
1995**Note**: A constant is used for only one specific function, that is, a constant cannot be used for multiple purposes.
1996
1997```cpp
1998// Good example: For protocol A and protocol B, the length of the MSISDN is 20.
1999const unsigned int A_MAX_MSISDN_LEN = 20;
2000const unsigned int B_MAX_MSISDN_LEN = 20;
2001
2002// Using different namespaces:
2003namespace Namespace1 {
2004    const unsigned int MAX_MSISDN_LEN = 20;
2005}
2006
2007namespace Namespace2 {
2008    const unsigned int MAX_MSISDN_LEN = 20;
2009}
2010```
2011
2012### Rule 9.1.4 Do not use memcpy_s or memset_s to initialize non-POD objects.
2013
2014**Note**: `POD` is short for `Plain Old Data`, which is a concept introduced in the C++ 98 standard (ISO/IEC 14882, first edition, 1998-09-01). The `POD` types include the original types and aggregate types such as `int`, `char`, `float`, `double`, `enumeration`, `void`, and pointer. Encapsulation and object-oriented features cannot be used (for example, user-defined constructors, assignment operators, destructors, base classes, and virtual functions).
2015
2016For non-POD classes, such as class objects of non-aggregate types, virtual functions may exist. Memory layout is uncertain, and is related to the compiler. Misuse of memory copies may cause serious problems.
2017
2018Even if a class of the aggregate type is directly copied and compared, and any functions hiding information or protecting data are destroyed, the `memcpy_s` and `memset_s` operations are not recommended.
2019
2020For details about the POD type, see the appendix.
2021
2022### Rec 9.1.2 Declare and initialize variables only when they are used.
2023
2024**Note**: It is a common low-level programming error that a variable is not assigned an initial value before being used. Declaring and initializing a variable just before using it will prevent this.
2025
2026If all variables are declared at the beginning of a function before they are used, their scope covers the entire function, which may lead to the following problems:
2027* The program may become difficult to understand and maintain. The definition and use of variables are separated.
2028* These variables are difficult to initialize properly. At the beginning of a function, there is often insufficient information for variable initialization, and a default null value (such as 0) is often assigned as the initial value. If a variable is used before it is assigned a valid value, it will also cause errors.
2029
2030Following the minimization principle of variable scopes and the principle of proximity declaration will make it easier to read code and understand variable types and initial values. In particular, use initialization to replace declaration and then assign values.
2031
2032```cpp
2033// Bad example: Declaration is separated from initialization.
2034string name;        // The variable is not initialized in the declaration, and a default constructor is called.
2035name = "zhangsan";  // An assignment operator is called again. Declaration is separate from definition, which is difficult to understand.
2036
2037// Good example: Declaration and initialization are together, and easy to understand.
2038string name("zhangsan");  // Invoke a constructor.
2039```
2040
2041
2042## Expressions
2043### Rule 9.2.1 A variable cannot be referenced again if it is contained in an increment or decrement operation in an expression.
2044In an expression where the increment or decrement operations are performed on a variable, the variable cannot be referenced again. The result of a second referencing is not explicitly defined in C++ standards. The results in different compilers or different versions of a compiler may be different.
2045Therefore, it is recommended that an undefined operation sequence not be assumed.
2046
2047Note that the problem of operation sequence cannot be solved by using parentheses because this is not a priority problem.
2048
2049Example:
2050```cpp
2051x = b[i] + i++; // Bad: Whether the position of b[i] is before or after the i++ is unclear.
2052```
2053The increment or decrement operation should be placed in a single line:
2054```cpp
2055x = b[i] + i;
2056i++;            // Good: i++ is placed in a single line.
2057```
2058
2059Function parameter
2060```cpp
2061Func(i++, i);   // Bad: Whether the increment operation happens for the second parameter is unclear
2062```
2063
2064Good example:
2065```cpp
2066i++;            // Good: i++ is placed in a single line.
2067x = Func(i, i);
2068```
2069
2070### Rule 9.2.2 A switch statement must have a default branch.
2071In most cases, a switch statement requires a default branch to ensure that there is a default action when the case tag is missing for a processed value.
2072
2073Exceptions:
2074
2075If the switch condition variables are enumerated and the case branch covers all values, the default branch is redundant.
2076
2077Because modern compilers can check which case branches are missing in the switch statement and provide an advanced warning.
2078
2079```cpp
2080enum Color {
2081    RED = 0,
2082    BLUE
2083};
2084
2085// The switch condition variables are enumerated. Therefore, you do not need to add a default branch.
2086switch (color) {
2087    case RED:
2088        DoRedThing();
2089        break;
2090    case BLUE:
2091        DoBlueThing();
2092        ...
2093        break;
2094}
2095```
2096
2097### Rec 9.2.1 When comparing expressions, follow the principle that the left side tends to change and the right side tends to remain unchanged.
2098When a variable is compared with a constant, placing the constant on the left, for example, if (MAX == v), does not comply with standard reading habits  and is more difficult to understand.
2099The constant should be placed on the right. The expression is written as follows:
2100```cpp
2101if (value == MAX) {
2102
2103}
2104
2105if (value < MAX) {
2106
2107}
2108```
2109There are special cases: for example, if the expression `if (MIN < value && value < MAX)` is used to describe a range, the first half, as a constant, should be placed on the left.
2110
2111You do not need to worry about writing '==' as '=' because a compilation alarm will be generated for `if (value = MAX)` and an error will be reported by other static check tools. Use these tools to solve such writing errors and ensure that that code is readable.
2112
2113### Rec 9.2.2 Use parentheses to specify the operator precedence.
2114Use parentheses to specify the operator precedence. This will prevent program errors due to the inconsistency between default priority and the intended design. At the same time, it makes the code clearer and more readable. However, too many parentheses muddy the code, reducing readability. The following is a recommendation on their correct usage.
2115
2116- For binary and ternary operators, if multiple operators are involved, parentheses should be used.
2117```cpp
2118x = a + b + c;        /* The operator does not change, and thus parentheses are not required. */
2119x = Foo(a + b, c);     /* The operator does not change, and thus parentheses are not required. */
2120x = 1 << (2 + 3);      /* More than one operator is used and thus parentheses are required. */
2121x = a + (b / 5);       /* More than one operator is used and thus parentheses are required. */
2122x = (a == b) ? a : (a – b);    /* More than one operator is used and thus parentheses are required. */
2123```
2124
2125
2126## Type Casting
2127
2128Do not use type branches to customize behaviors. Type branch customization behavior is prone to errors and is an obvious sign of attempting to compile C code using C++. This is very inflexible technology. If you forget to modify all branches when adding a new type to a compiler, you will not be notified. Use templates and virtual functions to let the type define itself rather than letting the calling side determine behavior.
2129
2130It is recommended that type casting be avoided. We should consider the data type in the code design instead of overusing type casting to solve type conflicts. When designing a basic type, consider the following:
2131- Whether it is unsigned or signed.
2132- Is it suitable for float or double?
2133- Should you use int8, int16, int32, or int64 bit lengths?
2134
2135However, we cannot prohibit the use of type casting because the C++ language is a machine-oriented programming language, involving pointer addresses, and we interact with various third-party or underlying APIs. Their type design may not be reasonable and type casting tends to occur in the adaptation process.
2136
2137Exception: When calling a function, if we do not want to process the result of the function, first consider whether this is your best choice. If you do not want to process the return value of the function, cast it to void.
2138
2139### Rule 9.3.1 If type casting is required, use the type casting provided by the C++ instead of the C style.
2140
2141**Note**:
2142
2143The type casting provided by C++ is more targeted, easy to read, and more secure than the C style. C++ provides the following types of casting:
2144- Type casting:
21451. `dynamic_cast`: Used to inherit the downstream transformation of the system. `dynamic_cast` has the type check function. Design the base class and derived class to avoid using dynamic_cast for casting.
21462. `static_cast`: Similar to the C style casting, which can be used to convert a value, or to convert the pointer or reference of a derived class into a base class pointer or reference. This casting is often used to eliminate type ambiguity brought on by multiple inheritance, which is relatively safe. If it is a pure arithmetic conversion, use the braces as stated in the following text.
21473. `reinterpret_cast`: Used to convert irrelevant types. `reinterpret_cast` forces the compiler to reinterpret the memory of a certain type of objects into another type, which is an unsafe conversion. It is recommended that `reinterpret_cast` be used as little as possible.
21484. `const_cast`: Used to remove the `const` attribute of an object so that the object can be modified. You are advised to use `const_cast` as little as possible.
2149
2150- Arithmetic conversion: (Supported by C++ 11 and later versions)
2151  If the type information is not lost, for example, the casting from float to double, or from int32 to int64, the braces syntax is recommended.
2152```cpp
2153  double d{ someFloat };
2154  int64_t i{ someInt32 };
2155```
2156
2157### Rec 9.3.1 Avoid using `dynamic_cast`.
21581. `dynamic_cast` depends on the RTTI of C++ so that the programmer can identify the type of the object in C++ at run time.
21592. `dynamic_cast` indicates that a problem has occurred in the design of the base class and derived class.The derived class destroys the contract of the base class and it is necessary to use `dynamic_cast` to convert the class to a subclass for special processing. In this case, it is more desirable to improve the design of the class, instead of using `dynamic_cast` to solve the problem.
2160
2161### Rec 9.3.2 Avoid using `reinterpret_cast`.
2162
2163**Note**: `reinterpret_cast` is used to convert irrelevant types. Trying to use `reinterpret_cast` to force a type to another type destroys the security and reliability of the type and is an insecure casting method. Avoid casting between completely different types.
2164
2165### Rec 9.3.3 Avoid using `const_cast`.
2166
2167**Note**: The `const_cast` command is used to remove the `const`  and `volatile` properties of an object.
2168
2169The action of using a pointer or reference after the const_cast conversion to modify the const property of an object is undefined.
2170
2171```cpp
2172// Bad example:
2173const int i = 1024;
2174int* p = const_cast<int*>(&i);
2175*p = 2048;      // The action is undefined.
2176```
2177
2178```cpp
2179// Bad example:
2180class Foo {
2181public:
2182    Foo() : i(3) {}
2183
2184    void Fun(int v)
2185    {
2186        i = v;
2187    }
2188
2189private:
2190    int i;
2191};
2192
2193int main(void)
2194{
2195    const Foo f;
2196    Foo* p = const_cast<Foo*>(&f);
2197    p->Fun(8);  // The action is undefined.
2198}
2199
2200```
2201
2202
2203## Resource Allocation and Release
2204
2205### Rule 9.4.1 When a single object is released, delete is used. When an array object is released, delete [] is used.
2206Note: To delete a single object, use delete; to delete an array object, use delete []. The reasons are as follows:
2207
2208- new: Apply for memory from the system and call the corresponding constructor to initialize an object.
2209- new[n]: Apply for memory for n objects and call the constructor n times for each object to initialize them.
2210- delete: Call the corresponding destructor first and release the memory of an object.
2211- delete[]: Call the corresponding destructor for each object and release their memory.
2212
2213If the usage of new and delete does not match this format, the results are unknown. For a non-class type, new and delete will not call the constructor or destructor.
2214
2215Bad example:
2216```cpp
2217const int MAX_ARRAY_SIZE = 100;
2218int* numberArray = new int[MAX_ARRAY_SIZE];
2219...
2220delete numberArray;
2221numberArray = NULL;
2222```
2223
2224Good example:
2225```cpp
2226const int MAX_ARRAY_SIZE = 100;
2227int* numberArray = new int[MAX_ARRAY_SIZE];
2228...
2229delete[] numberArray;
2230numberArray = NULL;
2231```
2232
2233### Rec 9.4.1 Use the RAII feature to trace dynamic allocation.
2234
2235Note: RAII is an acronym for Resource Acquisition Is Initialization. It is a simple technology that controls program resources (such as memory, file handle, network connections, and mutexes) by using the object lifecycle.
2236
2237The common practice is as follows: When the object is constructed, the resource is obtained, and the access to the resource is controlled so that the resource is always valid in the life cycle of the object. Finally, the resource is released when the object is destructed. This approach has two advantages:
2238- We do not need to explicitly release resources.
2239- The resources required by the object are always valid throughout the lifecycle of the object. This way, you do not need to check the validity of the resources, which simplifies logic and improves efficiency.
2240
2241
2242In the following example, RAII removes the need for explicit release of mutex resources.
2243
2244```cpp
2245class LockGuard {
2246public:
2247    LockGuard(const LockType& lockType): lock_(lockType)
2248    {
2249        lock_.Acquire();
2250    }
2251
2252    ~LockGuard()
2253    {
2254        lock_.Release();
2255    }
2256
2257private:
2258    LockType lock_;
2259};
2260
2261
2262bool Update()
2263{
2264    LockGuard lockGuard(mutex);
2265    if (...) {
2266        return false;
2267    } else {
2268        // Data operations
2269    }
2270
2271    return true;
2272}
2273```
2274
2275## Standard Template Library
2276
2277The standard template library (STL) varies between products. The following table lists some basic rules and suggestions for each team.
2278
2279### Rule 9.5.1 Do not save the pointer returned by c_str () of std::string.
2280
2281Note: The C++ standard does not specify that the string::c_str () pointer is permanently valid. Therefore, the STL implementation used can return a temporary storage area and release it quickly when calling string::c_str (). Therefore, to ensure the portability of the program, do not save the result of string::c_str (). Instead, call it directly.
2282
2283Example:
2284
2285```cpp
2286void Fun1()
2287{
2288    std::string name = "demo";
2289    const char* text = name.c_str(); // After the expression ends, the life cycle of name is still in use and the pointer is valid.
2290
2291    // If a non-const member function (such as operator[] and begin()) of the string type is invoked and the string is modified,
2292    // The text may become unavailable or may not be the original string.
2293    name = "test";
2294    name[1] = '2';
2295
2296    // When the text pointer is used next time, the string is no longer "demo".
2297}
2298
2299void Fun2()
2300{
2301    std::string name = "demo";
2302    std::string test = "test";
2303    const char* text = (name + test).c_str(); // After the expression ends, the temporary object generated by the + operator may be destroyed, and the pointer may be invalid.
2304
2305    // When the text pointer is used next time, it no longer points to the valid memory space.
2306}
2307```
2308Exception: In rare cases where high performance coding is required , you can temporarily save the pointer returned by string::c_str() to match the existing functions which support only the input parameters of the const char* type. However, you should ensure that the lifecycle of the string object is longer than that of the saved pointer, and that the string object is not modified within the lifecycle of the saved pointer.
2309
2310
2311### Rec 9.5.1 Use std::string instead of char*.
2312
2313Note: Using string instead of `char*` has the following advantages:
23141. There is no need to consider the null character '\0' at the end.
23152. You can directly use operators such as `+`,  `=`, and `==`, and other character and string operation functions.
23163. There is no need to consider memory allocation operations. This helps avoid explicit usage of `new` and `delete` and the resulting errors.
2317
2318Note that in some STL implementations, string is based on the copy-on-write policy, which causes two problems. One is that the copy-on-write policy of some versions does not implement thread security, and the program breaks down in multi-threaded environments. Second, dangling pointers may be caused when a dynamic link library transfers the string based on the copy-on-write policy, due to the fact that reference count cannot be reduced when the library is unloaded. Therefore, it is important to select a reliable STL implementation to ensure the stability of the program.
2319
2320Exception:
2321
2322When an API of a system or other third-party library is called, only `char*` can be used for defined interfaces. However, before calling the interfaces, you can use string. When calling the interfaces, you can use `string::c_str()` to obtain the character pointer.
2323
2324When a character array is allocated as a buffer on the stack, you can directly define the character array without using string or containers such as `vector<char>`.
2325
2326### Rule 9.5.2 Do not use auto_ptr.
2327Note: The `std::auto_ptr` in the STL library has an implicit ownership transfer behavior. The code is as follows:
2328```cpp
2329auto_ptr<T> p1(new T);
2330auto_ptr<T> p2 = p1;
2331```
2332After the second line of statements is executed, p1 does not point to the object allocated in line 1 and becomes `NULL`. Therefore, `auto_ptr` cannot be placed in any standard containers.
2333
2334This ownership transfer behavior is not expected. In scenarios where ownership must be transferred, implicit transfer should not be used. This often requires the programmer to keep extra attention on code that uses `auto_ptr`, otherwise access to a null pointer will occur.
2335
2336There are two common scenarios for using auto_ptr . One is to transfer it as a smart pointer to outside the function that generates the auto_ptr , and the other is to use auto_ptr as the RAII management class. Resources are automatically released when the lifecycle of auto_ptr expires.
2337
2338In the first scenario, you can use std::shared_ptr instead.
2339
2340In the second scenario, you can use std::unique_ptr in the C++ 11 standard. std::unique_ptr is a substitute for std::auto_ptr and supports explicit ownership transfer.
2341
2342Exception:
2343
2344Before the C++ 11 standard is widely used, std::auto_ptr can be used in scenarios where ownership needs to be transferred. However, it is recommended that std::auto_ptr be encapsulated. The copy constructor and assignment operator of the encapsulation class should not be used in a standard container.
2345
2346
2347### Rec 9.5.2 Use the new standard header files.
2348
2349Note:
2350When using the standard header file of C++, use `<cstdlib>` instead of `<stdlib.h>`.
2351
2352## Usage of const
2353Add the keyword const before the declared variable or parameter (example: `const int foo`) to prevent the variable from being tampered with. Add the const qualifier to the function in the class (example: `class Foo {int Bar (char c) const;} ;`) to make sure the function does not modify the status of the class member variable. const variables, data members, functions, and parameters ensure that the type detection during compilation is accurate and errors are found as soon as possible. Therefore, we strongly recommend that const be used in any possible case.
2354
2355Sometimes it is better to use constexpr from C++ 11 to define real constants.
2356
2357### Rule 9.6.1 For formal parameters of pointer and reference types, if the parameters do not need to be modified, use const.
2358Unchanging values are easier to understand, trace, and analyze. `const` is used as the default option and is checked during compilation to make the code more secure and reliable.
2359```cpp
2360class Foo;
2361
2362void PrintFoo(const Foo& foo);
2363```
2364
2365### Rule 9.6.2 For member functions that do not modify member variables, use const.
2366Declare the member function as `const` whenever possible. The access function should always be const. So long as the function of a member is not modified, the function is declared with const.
2367
2368When you need to modify data members in a virtual function, take all classes in the inheritance chain into account instead of only focusing on the implementation of a single class.
2369
2370```cpp
2371class Foo {
2372public:
2373
2374    // ...
2375
2376    int PrintValue() const // const modifies member functions and does not modify member variables.
2377    {
2378        std::cout << value_ << std::endl;
2379    }
2380
2381    int GetValue() const  // const modifies member functions and does not modify member variables.
2382    {
2383        return value_;
2384    }
2385
2386private:
2387    int value_;
2388};
2389```
2390
2391### Rec 9.6.1 Member variables that will not be modified after initialization should be defined as constants.
2392
2393```cpp
2394class Foo {
2395public:
2396    Foo(int length) : dataLength_(length) {}
2397private:
2398    const int dataLength_;
2399};
2400```
2401
2402## Exceptions
2403
2404### Rec 9.7.1 If the function does not throw an exception, the declaration is `noexcept`.
2405**Reasons:**
24061. If the function does not throw an exception, the declaration is `noexcept`, which enables the compiler to optimize the function to the maximum extent, for example, reducing the execution paths and improving the efficiency of exiting when an error occurs.
24072. For STL containers such as  `vector`, to ensure the interface robustness, if the `move `  constructor of saved items is not declared as `noexcept`,  the `copy machanism` instead of the  `move machanism`  is used when the items are removed from the container. This would cause performance loss risks. If the function does not throw an exception, or a program does not intercept and process an exception thrown by the function, new `noexcept` keywords can be used to modify the function, indicating that the function does not throw an exception or the thrown exception is not intercepted or processed. For example:
2408
2409```cpp
2410extern "C" double sqrt(double) noexcept;  // No exceptions are thrown.
2411
2412// noexcept can still be used when exceptions may be thrown.
2413// The exception of memory exhaustion is not processed. The function is simply declared as noexcept.
2414std::vector<int> MyComputation(const std::vector<int>& v) noexcept
2415{
2416    std::vector res = v;    // Exceptions may be thrown.
2417    // do something
2418    return res;
2419}
2420```
2421
2422**Example**
2423
2424```cpp
2425RetType Function(Type params) noexcept;   // Maximized optimization
2426RetType Function(Type params) noexcept;   // No optimization
2427
2428// Declaration as noexcept for the move operation of std::vector is needed.
2429class Foo1 {
2430public:
2431    Foo1(Foo1&& other);  // no noexcept
2432};
2433
2434std::vector<Foo1> a1;
2435a1.push_back(Foo1());
2436a1.push_back(Foo1()); // The copy constructor is called to enable the container expansion and removal of existing items.
2437
2438class Foo2 {
2439public:
2440    Foo2(Foo2&& other) noexcept;
2441};
2442
2443std::vector<Foo2> a2;
2444a2.push_back(Foo2());
2445a2.push_back(Foo2()); //Triggers container expansion and invokes the move constructor to move existing elements.
2446```
2447
2448**Note**
2449
2450The default constructor, destructor, `swap` function, and `move` operator should not throw an exception.
2451
2452## Templates and Generic Programming
2453
2454### Rule 9.8.1 Do not use generic programming.
2455OpenHarmony adopts object-oriented programming, which has ideas, concepts, and techniques totally different from those of generic programming.
2456
2457Generic programming in C++ allows for extremely flexible interfaces that are type safe and high performance, enabling reuse of code of different types but with the same behavior.
2458
2459However, generic programming has the following disadvantages:
2460
24611. People who are not familiar with generic programming often write into templates object-oriented logic or members that do not depend on template parameters, making the code unreadable or bloated.
24622. The techniques used in generic programming are often obscure to anyone but language experts. Template code can be unreadable in certain cases.
24633. Generic programming often leads to extremely poor compile time error messages. The uncalled-for implementation details of APIs are displayed to users in the error messages, making even a simple API difficult to debug.
24644. Inappropriate use of templates cause code bloat during runtime.
24655. It is difficult to modify or refactor the template code. The template code is expanded in multiple contexts, and it is hard to verify that the code refactoring makes sense in all of them.
2466
2467Only __a few components of OpenHarmony__ support generic programming, and the templates developed using generic programming must have detailed comments.
2468
2469Exceptions:
2470
2471The STL adaptation layer can use generic programming.
2472
2473## Macros
2474In the C++ language, it is strongly recommended that complex macros be used as little as possible.
2475- For constant definitions, use `const` or `enum` as stated in the preceding sections.
2476- For macro functions, try to be as simple as possible, comply with the following principles, and use inline functions and template functions for replacement.
2477
2478```cpp
2479// The macro function is not recommended.
2480#define SQUARE(a, b) ((a) * (b))
2481
2482// Use the template function and inline function as a replacement.
2483template<typename T> T Square(T a, T b) { return a * b; }
2484```
2485
2486For details about how to use macros, see the related chapters about the C language specifications.
2487**Exception**: For some common and mature applications, for example, encapsulation for new and delete, the use of macros can be retained.
2488
2489# 10 Modern C++ Features
2490
2491As the ISO released the C++ 11 language standard in 2011 and released the C++ 17 in March 2017, the modern C++ (C++ 11/14/17) adds a large number of new language features and standard libraries that improve programming efficiency and code quality.
2492This chapter describes some guidelines for modern C++ use, to avoid language pitfalls.
2493
2494## Code Simplicity and Security Improvement
2495### Rec 10.1.1 Use `auto` properly.
2496**Reasons**
2497
2498* `auto` can help you avoid writing verbose, repeated type names, and can also ensure initialization when variables are defined.
2499* The `auto` type deduction rules are complex and need to be read carefully.
2500* If using `auto` makes the code clearer, use a specific type of it and use it only for local variables.
2501
2502**Example**
2503
2504```cpp
2505// Avoid verbose type names.
2506std::map<string, int>::iterator iter = m.find(val);
2507auto iter = m.find(val);
2508
2509// Avoid duplicate type names.
2510class Foo {...};
2511Foo* p = new Foo;
2512auto p = new Foo;
2513
2514// Ensure that the initialization is successful.
2515int x;    // The compilation is correct but the variable is not initialized.
2516auto x;   // The compilation failed. Initialization is needed.
2517```
2518
2519`auto` type deduction may cause the following problems:
2520
2521```cpp
2522auto a = 3;           // int
2523const auto ca = a;    // const int
2524const auto& ra = a;   // const int&
2525auto aa = ca;         // int, const and reference are neglected.
2526auto ila1 = { 10 };   // std::initializer_list<int>
2527auto ila2{ 10 };      // std::initializer_list<int>
2528
2529auto&& ura1 = x;      // int&
2530auto&& ura2 = ca;     // const int&
2531auto&& ura3 = 10;     // int&&
2532
2533const int b[10];
2534auto arr1 = b;        // const int*
2535auto& arr2 = b;       // const int(&)[10]
2536```
2537
2538If you do not pay attention to `auto` type deduction and ignore the reference, hard-to-find performance problems may be created.
2539
2540```cpp
2541std::vector<std::string> v;
2542auto s1 = v[0]; // auto deduction changes s1 to std::string in order to copy v[0].
2543```
2544
2545If `auto` is used to define an interface, such as a constant in a header file, the type may be changed if the developer has modified the value.
2546
2547### Rule 10.1.1 Use the keyword `override` when rewriting virtual functions.
2548**Reason**
2549
2550The keyword `override` ensures that the function is a virtual function and an overridden virtual function of the base class. If the subclass function is different from the base class function prototype, a compilation alarm is generated. `final` also ensures that virtual functions are not overridden by subclasses.
2551
2552If you modify the prototype of a base class virtual function but forget to modify the virtual function overridden by the subclass, you can find inconsistency during compilation. You can also avoid forgetting to modify the overridden function when there are multiple subclasses.
2553
2554**Example**
2555
2556```cpp
2557class Base {
2558public:
2559    virtual void Foo();
2560    virtual void Foo(int var);
2561    void Bar();
2562};
2563
2564class Derived : public Base {
2565public:
2566    void Foo() const override; // Compilation failed: derived::Foo is different from that of the prototype of base::Foo and is not overridden.
2567    void Foo() override;       // Compilation successful: derived::Foo overrode base::Foo.
2568    void Foo(int var) final;   // Compilation successful: Derived::Foo(int) rewrites Base::Foo(int), and the derived class of Derived cannot override this function.
2569    void Bar() override;       // Compilation failed: base::Bar is not a virtual function.
2570};
2571```
2572
2573**Summary**
25741. When defining the virtual function for the first time based on the base class, use the keyword `virtual`.
25752. When overriding the virtual function by a subclass in a base class, including destructors, use the keyword `override` or  `final` instead of `virtual`.
25763. For the non-virtual function, do not use `virtual` or `override`.
2577
2578### Rule: 10.1.2 Use the keyword `delete` to delete functions.
2579**Reason**
2580
2581The `delete` keyword is clearer and the application scope is wider than a class member function that is declared as private and not implemented.
2582
2583**Example**
2584
2585```cpp
2586class Foo {
2587private:
2588    // Whether the copy structure is deleted or not is unknown because usually only the header file is checked.
2589    Foo(const Foo&);
2590};
2591
2592class Foo {
2593public:
2594    // Explicitly delete the copy assignment operator.
2595    Foo& operator=(const Foo&) = delete;
2596};
2597```
2598
2599The `delete` keyword can also be used to delete non-member functions.
2600
2601```cpp
2602template<typename T>
2603void Process(T value);
2604
2605template<>
2606void Process<void>(void) = delete;
2607```
2608
2609### Rule 10.1.3 Use `nullptr` instead of `NULL` or `0`.
2610**Reason**
2611
2612For a long time, C++ has not had a keyword that represents a null pointer, which is embarrassing:
2613
2614```cpp
2615#define NULL ((void *)0)
2616
2617char* str = NULL;   // Error: void* cannot be automatically converted to char*.
2618
2619void(C::*pmf)() = &C::Func;
2620if (pmf == NULL) {} // Error: void* cannot be automatically converted to the pointer that points to the member function.
2621```
2622
2623If `NULL` is defined as `0` or `0L`, the above problems can be solved.
2624
2625Alternatively, use `0` directly in places where null pointers are required. However, another problem occurs. The code is not clear, especially when `auto` is used for automatic deduction.
2626
2627```cpp
2628auto result = Find(id);
2629if (result == 0) {  // Does Find() return a pointer or an integer?
2630    // do something
2631}
2632```
2633
2634Literally `0` is of the `int` type (`0L` is the `long` type). Therefore, neither `NULL` nor `0` is a pointer type.
2635When a function of the pointer or integer type is overloaded, `NULL` or `0` calls only the overloaded pointer function.
2636
2637```cpp
2638void F(int);
2639void F(int*);
2640
2641F(0);      // Call F(int) instead of F(int*).
2642F(NULL);   // Call F(int) instead of F(int*).
2643```
2644
2645In addition, `sizeof(NULL) == sizeof(void*)` does not always make sense, which is a potential risk.
2646
2647Summary: If `0` or `0L` is directly used, the code is not clear and type security cannot be ensured. If `NULL` is used, the type security cannot be ensured. These are all potential risks.
2648
2649`nullptr` has many advantages. It literally represents the null pointer and makes the code clearer. More to the point, it is no longer an integer type.
2650
2651`nullptr` is of the `std::nullptr_t` type. `std::nullptr_t` can be implicitly converted into all original pointer types, so that `nullptr` can represent a null pointer that points to any type.
2652
2653```cpp
2654void F(int);
2655void F(int*);
2656F(nullptr);   // Call F(int*).
2657
2658auto result = Find(id);
2659if (result == nullptr) {  // Find() returns a pointer.
2660    // do something
2661}
2662```
2663
2664### Rule 10.1.4 Use `using` instead of `typedef`.
2665For versions earlier than `C++11`, you can define the alias of the type by using `typedef`. No one wants to repeat code like `std::map<uint32_t, std::vector<int>>`.
2666
2667```cpp
2668typedef std::map<uint32_t, std::vector<int>> SomeType;
2669```
2670
2671Using alias for the type is actually encapsulating the type. This encapsulation makes the code clearer, and to a large extent avoids the bulk modification caused by the type change.
2672For versions supporting C++ 11 features, `using` is provided to implement `alias declarations`:
2673
2674```cpp
2675using SomeType = std::map<uint32_t, std::vector<int>>;
2676```
2677
2678Compare the two formats:
2679
2680```cpp
2681typedef Type Alias;   // It cannot be told whether the original Type or Alias is at the front.
2682using Alias = Type;   // The format confirms to the assignment rule. It is easy to understand and helps reduce errors.
2683```
2684
2685If this is not enough to prove the advantages of `using`, the alias template may be a better example:
2686
2687```cpp
2688//: Only one line of code is need to define an alias for a template.
2689template<class T>
2690using MyAllocatorVector = std::vector<T, MyAllocator<T>>;
2691
2692MyAllocatorVector data;       // An alias for a template defined with "using".
2693
2694template<class T>
2695class MyClass {
2696private:
2697    MyAllocatorVector data_;   // Another.
2698};
2699```
2700
2701`typedef` does not support alias templates and they have to be hacked in.
2702
2703```cpp
2704// A template is used for packaging typedef. Therefore, a template class is needed.
2705template<class T>
2706struct MyAllocatorVector {
2707    typedef std::vector<T, MyAllocator<T>> type;
2708};
2709
2710MyAllocatorVector::type data;  // ::type needs to be added when using typedef to define an alias.
2711
2712template<class T>
2713class MyClass {
2714private:
2715    typename MyAllocatorVector::type data_;  // For a template class, typename is also needed in addition to ::type.
2716};
2717```
2718
2719### Rule 10.1.5 Do not use std::move to operate the const object.
2720Literally, `std::move` means moving an object. The const object cannot be modified and cannot be moved. Therefore, using `std::move` to operate the const object may confuse code readers.
2721
2722Regarding actual functions, `std::move` converts an object to the rvalue reference type. It can convert the const object to the rvalue reference of const. Because few types define the move constructor and the move assignment operator that use the const rvalue reference as the parameter, the actual function of code is often degraded to object copy instead of object movement, which brings performance loss.
2723
2724**Bad example**
2725
2726```cpp
2727std::string g_string;
2728std::vector<std::string> g_stringList;
2729
2730void func()
2731{
2732    const std::string myString = "String content";
2733    g_string = std::move(myString); // Bad: myString is not moved. Instead, it is copied.
2734    const std::string anotherString = "Another string content";
2735    g_stringList.push_back(std::move(anotherString));    // Bad: anotherString is not moved. Instead, it is copied.
2736}
2737```
2738
2739## Smart Pointers
2740### Rule 10.2.1 Preferentially use the original pointer instead of the smart pointer for singletons and class members that are not held by multiple parties.
2741**Reason**
2742Smart pointers automatically release object resources to prevent resource leakage, but they require extra resource overheads. For example, the classes, constructors, and destructors automatically generated by smart pointers consume more resources such as memory.
2743
2744When singletons, class members, and the like are not held by multiple parties, resources can be released only in class destructors. In this case, smart pointers should not be used.
2745
2746**Example**
2747
2748```cpp
2749class Foo;
2750class Base {
2751public:
2752    Base() {}
2753    virtual ~Base()
2754    {
2755        delete foo_;
2756    }
2757private:
2758    Foo* foo_ = nullptr;
2759};
2760```
2761
2762**Exceptions**
27631. When a created object is returned, a smart pointer can be used if the pointer destructor is required.
2764```cpp
2765class User;
2766class Foo {
2767public:
2768    std::unique_ptr<User, void(User *)> CreateUniqueUser() // Use unique_ptr to ensure that the object is created and released in the same runtime.
2769    {
2770        sptr<User> ipcUser = iface_cast<User>(remoter);
2771        return std::unique_ptr<User, void(User *)>(::new User(ipcUser), [](User *user) {
2772            user->Close();
2773            ::delete user;
2774        });
2775    }
2776
2777    std::shared_ptr<User> CreateSharedUser() // Use shared_ptr to ensure that the object is created and released in the same runtime.
2778    {
2779        sptr<User> ipcUser = iface_cast<User>(remoter);
2780        return std::shared_ptr<User>(ipcUser.GetRefPtr(), [ipcUser](User *user) mutable {
2781            ipcUser = nullptr;
2782        });
2783    }
2784};
2785```
27862. When the created object is returned and needs to be referenced by multiple parties, `shared_ptr` can be used.
2787
2788### Rule 10.2.2 Use `unique_ptr` instead of `shared_ptr`.
2789**Reasons**
2790
27911. Using `shared_ptr` a lot has an overhead (atomic operations on the `shared_ptr`s reference count have a measurable cost).
27922. Shared ownership in some cases (such as circular dependency) may create objects that can never be released.
27933. Shared ownership can be an attractive alternative to careful ownership design but it may obfuscate the design of a system.
2794
2795### Rule 10.2.2 Use `std::make_unique` instead of `new` to create a `unique_ptr`.
2796**Reasons**
2797
27981. `make_unique` provides a simpler creation method.
27992. `make_unique` ensures the exception safety of complex expressions.
2800
2801**Example**
2802
2803```cpp
2804// Bad: MyClass appears twice, which carries a risk of inconsistency.
2805std::unique_ptr<MyClass> ptr(new MyClass(0, 1));
2806// Good: MyClass appears once and there is no possibility of inconsistency.
2807auto ptr = std::make_unique<MyClass>(0, 1);
2808```
2809
2810Recurrence of types may cause serious problems, and it is difficult to find them:
2811
2812```cpp
2813// The code compiles fine, but new and delete usage does not match.
2814std::unique_ptr<uint8_t> ptr(new uint8_t[10]);
2815std::unique_ptr<uint8_t[]> ptr(new uint8_t);
2816// No exception safety: The compiler may calculate parameters in the following order:
2817// 1. Allocate the memory of Foo.
2818// 2. Construct Foo.
2819// 3. Call Bar.
2820// 4. Construct unique_ptr<Foo>.
2821// If Bar throws an exception, Foo is not destroyed and a memory leak occurs.
2822F(unique_ptr<Foo>(new Foo()), Bar());
2823
2824// Exception safety: Calling of function is not interrupted.
2825F(make_unique<Foo>(), Bar());
2826```
2827
2828**Exception**
2829
2830`std::make_unique` does not support user-defined `deleter`.
2831
2832In the scenario where the `deleter` needs to be customized, it is recommended that `make_unique` be implemented in the customized version's own namespace.
2833
2834Using `new` to create `unique_ptr` with the user-defined `deleter` is the last choice.
2835
2836### Rule 10.2.4 Create `shared_ptr` by using `std::make_shared` instead of `new`.
2837**Reason**
2838
2839In addition to the consistency factor similar to that in `std::make_unique` when using `std::make_shared`, performance is also a factor to consider.
2840`std::shared_ptr` manages two entities:
2841
2842* Control block (storing reference count, `deleter`, etc.)
2843* Managed objects
2844
2845When `std::make_shared` creates `std::shared_ptr`, it allocates sufficient memory for storing control blocks and managed objects on the heap at a time. When `std::shared_ptr<MyClass>(new MyClass)`is used to create a `std::shared_ptr`, not only does `new MyClass` trigger heap allocation, but the constructor function of `std::shard_ptr` triggers a second heap allocation, resulting in extra overhead.
2846
2847**Exception**
2848
2849Similar to `std::make_unique`, `std::make_shared` does not support `deleter` customization.
2850
2851## Lambda
2852### Rec 10.3.1 Use `lambda` to capture local variables or write local functions when normal functions do not work.
2853**Reason**
2854
2855Functions cannot capture local variables or be declared at local scope. If you need those things, choose `lambda` instead of handwritten `functor`.
2856
2857On the other hand, `lambda` and `functor` objects do not support overloading. If overloading is required, use a function.
2858
2859If both `lambda` and functions work, a function is preferred. Use the simplest tool.
2860
2861**Example**
2862
2863```cpp
2864// Write a function that accepts only an int or string.
2865// -- Overloading is more natural.
2866void F(int);
2867void F(const string&);
2868
2869// The local state needs to be captured or appear in the statement or expression range.
2870// -- A lambda is more natural.
2871vector<Work> v = LotsOfWork();
2872for (int taskNum = 0; taskNum < max; ++taskNum) {
2873    pool.Run([=, &v] {...});
2874}
2875pool.Join();
2876```
2877
2878### Rule 10.3.1 Avoid capturing by reference in lambdas that will not be used locally.
2879**Reason**
2880
2881Using `lambdas` at a "nonlocal" scope includes returning, storing on the heap, and passing to another thread. Local pointers and references should not outlive their scope. Capturing by reference in `lambdas` indicates storing a reference to a local object. If this leads to a reference that exceeds the lifecycle of a local variable, capturing by reference should not be used.
2882
2883**Example**
2884
2885```cpp
2886// Bad
2887void Foo()
2888{
2889    int local = 42;
2890    // Capture a reference to a local variable.
2891    // After the function returns results, local no longer exists,
2892    // Process() call will have undefined behavior.
2893    threadPool.QueueWork([&]{ Process(local); });
2894}
2895
2896// Good
2897void Foo()
2898{
2899    int local = 42;
2900    // Capture a copy of local.
2901    // Since a copy of local is made, it will be always available for the call.
2902    threadPool.QueueWork([=]{ Process(local); });
2903}
2904```
2905
2906### Rec 10.3.2 All variables are explicitly captured if `this` is captured.
2907**Reason**
2908
2909The `[=]` in the member function seems to indicate capturing by value but actually it is capturing data members by reference because it captures the invisible `this` pointer by value. Generally, it is recommended that capturing by reference be avoided. If it is necessary to do so, write `this` explicitly.
2910
2911**Example**
2912
2913```cpp
2914class MyClass {
2915public:
2916    void Foo()
2917    {
2918        int i = 0;
2919
2920        auto Lambda = [=]() { Use(i, data_); };   // Bad: It looks like we are copying or capturing by value but member variables are actually captured by reference.
2921
2922        data_ = 42;
2923        Lambda(); // Call use(42);
2924        data_ = 43;
2925        Lambda(); // Call use(43);
2926
2927        auto Lambda2 = [i, this]() { Use(i, data_); }; // Good: the most explicit and least confusing method.
2928    }
2929
2930private:
2931    int data_ = 0;
2932};
2933```
2934
2935### Rec 10.3.3 Avoid default capture modes.
2936**Reason**
2937
2938The lambda expression provides two default capture modes: by-reference (&) and by-value (=).
2939
2940By default, the "by-reference" capture mode will implicitly capture the reference of all local variables, which will easily lead to dangling references. By contrast, explicitly writing variables that need to be captured can make it easier to check the lifecycle of an object and reduce the possibility of making a mistake.
2941
2942By default, the "by-value" capture mode will implicitly capture this pointer, and it is difficult to find out which variables the lambda function depends on. If a static variable exists, the reader mistakenly considers that the lambda has copied a static variable.
2943
2944Therefore, it is required to clearly state the variables that lambda needs to capture, instead of using the default capture mode.
2945
2946**Bad example**
2947
2948```cpp
2949auto func()
2950{
2951    int addend = 5;
2952    static int baseValue = 3;
2953
2954    return [=]() {  // Only addend is actually copied.
2955        ++baseValue;    // The modification will affect the value of the static variable.
2956        return baseValue + addend;
2957    };
2958}
2959```
2960
2961**Good example**
2962
2963```cpp
2964auto func()
2965{
2966    int addend = 5;
2967    static int baseValue = 3;
2968
2969    return [addend, baseValue = baseValue]() mutable {  // Uses the C++14 capture initialization to copy a variable.
2970        ++baseValue;    // Modifying the copy of a static variable does not affect the value of the static variable.
2971        return baseValue + addend;
2972    };
2973}
2974```
2975
2976Reference: Effective Modern C++: Item 31: Avoid default capture modes.
2977
2978## Interfaces
2979### Rec 10.4.1 Use `T*` or `T&` arguments instead of a smart pointer in scenarios where ownership is not involved.
2980**Reasons**
2981
29821. Passing a smart pointer to transfer or share ownership should only be used when the ownership mechanism is explicitly required.
29832. Passing a smart pointer (for example, passing `this` ) restricts the use of a function to callers using smart pointers.
29843. Passing a shared smart pointer adds a runtime performance cost.
2985
2986**Example**
2987
2988```cpp
2989// Accept any int*.
2990void F(int*);
2991
2992// Accept only integers for which you want to transfer ownership.
2993void G(unique_ptr<int>);
2994
2995// Accept only integers for which you want to share ownership.
2996void G(shared_ptr<int>);
2997
2998// Does not need to change the ownership but requires ownership of the caller.
2999void H(const unique_ptr<int>&);
3000
3001// Accept any int.
3002void H(int&);
3003
3004// Bad
3005void F(shared_ptr<Widget>& w)
3006{
3007    // ...
3008    Use(*w); // When only w is used, lifecycle management is not required.
3009    // ...
3010};
3011```
3012