Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
Docs
提交
5a2c190c
D
Docs
项目概览
OpenHarmony
/
Docs
大约 1 年 前同步成功
通知
159
Star
292
Fork
28
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
Docs
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
5a2c190c
编写于
6月 06, 2022
作者:
O
openharmony_ci
提交者:
Gitee
6月 06, 2022
浏览文件
操作
浏览文件
下载
差异文件
!4958 优化OpenHarmony-cpp-coding-style-guide.md
Merge pull request !4958 from Tianshi Liu/master
上级
7b36562c
b9249411
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
107 addition
and
107 deletion
+107
-107
zh-cn/contribute/OpenHarmony-cpp-coding-style-guide.md
zh-cn/contribute/OpenHarmony-cpp-coding-style-guide.md
+107
-107
未找到文件。
zh-cn/contribute/OpenHarmony-cpp-coding-style-guide.md
浏览文件 @
5a2c190c
# C++语言编程规范
## <a name="c0-1"></a>目的
规则并不是完美的,通过禁止在特定情况下有用的特性,可能会对代码实现造成影响。但是我们制定规则的目的“为了大多数程序员可以得到更多的好处”, 如果在团队运作中认为某个规则无法遵循,希望可以共同改进该规则。
参考该规范之前,希望您具有相应的C++语言基础能力,而不是通过该文档来学习C++语言。
规则并不是完美的,通过禁止在特定情况下有用的特性,可能会对代码实现造成影响。但是我们制定规则的目的“为了大多数程序员可以得到更多的好处”, 如果在团队运作中认为某个规则无法遵循,希望可以共同改进该规则。
参考该规范之前,希望您具有相应的C++语言基础能力,而不是通过该文档来学习C++语言。
1.
了解C++语言的ISO标准;
2.
熟知C++语言的基本语言特性,包括C++ 03/11/14/17相关特性;
3.
了解C++语言的标准库;
## <a name="c0-2"></a>总体原则
代码需要在保证功能正确的前提下,满足
**可读、可维护、安全、可靠、可测试、高效、可移植**
的特征要求。
代码需要在保证功能正确的前提下,满足
**可读、可维护、安全、可靠、可测试、高效、可移植**
的特征要求。
## <a name="c0-2"></a> 重点关注
1.
约定C++语言的编程风格,比如命名,排版等。
...
...
@@ -31,8 +31,8 @@
在不违背总体原则,经过充分考虑,有充足的理由的前提下,可以适当违背规范中约定。
例外破坏了代码的一致性,请尽量避免。'规则'的例外应该是极少的。
下列情况,应风格一致性原则优先:
**修改外部开源代码、第三方代码时,应该遵守开源代码、第三方代码已有规范,保持风格统一。**
下列情况,应风格一致性原则优先:
**修改外部开源代码、第三方代码时,应该遵守开源代码、第三方代码已有规范,保持风格统一。**
# <a name="c2"></a>2 命名
## <a name="c2-1"></a>通用命名
...
...
@@ -112,11 +112,11 @@ enum UrlTableErrors { ...
```
cpp
// namespace
namespace
OsUtils
{
namespace
FileUtils
{
}
}
```
...
...
@@ -153,7 +153,7 @@ int g_activeConnectCount;
void
Func
()
{
static
int
packetCount
=
0
;
static
int
packetCount
=
0
;
...
}
```
...
...
@@ -253,7 +253,7 @@ int Foo(int a)
class
MyClass
{
public:
MyClass
()
:
value_
(
0
)
{}
private:
int
value_
;
};
...
...
@@ -305,7 +305,7 @@ ReturnType result = FunctionName(paramName1,
paramName2
,
// Good:保持与上方参数对齐
paramName3
);
ReturnType
result
=
FunctionName
(
paramName1
,
paramName2
,
ReturnType
result
=
FunctionName
(
paramName1
,
paramName2
,
paramName3
,
paramName4
,
paramName5
);
// Good:参数换行,4 空格缩进
ReturnType
result
=
VeryVeryVeryLongFunctionName
(
// 行宽不满足第1个参数,直接换行
...
...
@@ -340,7 +340,7 @@ if (objectIsNotExist) { // Good:单行条件语句也加大括号
如下是正确的写法:
```
cpp
if
(
someConditions
)
{
if
(
someConditions
)
{
DoSomething
();
...
}
else
{
// Good: else 与 if 在不同行
...
...
@@ -507,40 +507,40 @@ int&p = i; // Bad
编译预处理的"#"统一放在行首,即使编译预处理的代码是嵌入在函数体中的,"#"也应该放在行首。
### <a name="r3-13-2"></a>规则3.13.2 避免使用宏
宏会忽略作用域,类型系统以及各种规则,容易引发问题。应尽量避免使用宏定义,如果必须使用宏,要保证证宏名的唯一性。
在C++中,有许多方式来避免使用宏:
-
用const或enum定义易于理解的常量
-
用namespace避免名字冲突
-
用inline函数避免函数调用的开销
-
用template函数来处理多种类型
宏会忽略作用域,类型系统以及各种规则,容易引发问题。应尽量避免使用宏定义,如果必须使用宏,要保证证宏名的唯一性。
在C++中,有许多方式来避免使用宏:
-
用const或enum定义易于理解的常量
-
用namespace避免名字冲突
-
用inline函数避免函数调用的开销
-
用template函数来处理多种类型
在文件头保护宏、条件编译、日志记录等必要场景中可以使用宏。
### <a name="r3-13-3"></a>规则3.13.3 禁止使用宏来表示常量
宏是简单的文本替换,在预处理阶段完成,运行报错时直接报相应的值;跟踪调试时也是显示值,而不是宏名; 宏没有类型检查,不
宏
全; 宏没有作用域。
宏是简单的文本替换,在预处理阶段完成,运行报错时直接报相应的值;跟踪调试时也是显示值,而不是宏名; 宏没有类型检查,不
安
全; 宏没有作用域。
### <a name="r3-13-4"></a>规则3.13.4 禁止使用函数式宏
宏义函数式宏前,应考虑能否用函数替代。对于可替代场景,建议用函数替代宏。
函数式宏的缺点如下:
-
函数式宏缺乏类型检查,不如函数调用检查严格
-
宏展开时宏参数不求值,可能会产生非预期结果
-
宏没有独
产的作用域
函数式宏的缺点如下:
-
函数式宏缺乏类型检查,不如函数调用检查严格
-
宏展开时宏参数不求值,可能会产生非预期结果
-
宏没有独
立的作用域
-
宏的技巧性太强,例如#的用法和无处不在的括号,影响可读性
-
在特定场景中必须用编译器对宏的扩展语法,如GCC的statement expression,影响可移植性
-
宏在预编译阶段展开后,在期后编译、链接和调试时都不可见;而且包含多行的宏会展开为一行。函数式宏难以调试、难以打断点,不利于定位问题
-
对于包含大量语句的宏,在每个调用点都要展开。如果调用点很多,会造成代码空间的膨胀
-
在特定场景中必须用编译器对宏的扩展语法,如GCC的statement expression,影响可移植性
-
宏在预编译阶段展开后,在期后编译、链接和调试时都不可见;而且包含多行的宏会展开为一行。函数式宏难以调试、难以打断点,不利于定位问题
-
对于包含大量语句的宏,在每个调用点都要展开。如果调用点很多,会造成代码空间的膨胀
函数没有宏的上述缺点。但是,函数相比宏,最大的劣势是执行效率不高(增加函数调用的开销和编译器优化的难度)。
为此,可以在必要时使用内联函数。内联函数跟宏类似,也是在调用点展开。不同之处在于内联函数是在编译时展开。
内联函数兼具函数和宏的优点:
-
内联函数执行严格的类型检查
内联函数兼具函数和宏的优点:
-
内联函数执行严格的类型检查
-
内联函数的参数求值只会进行一次
-
内联函数就地展开,没有函数调用的开销
-
内联函数比函数优化得更好
对于性能要求高的产品代码,可以考虑用内联函数代替函数。
-
内联函数比函数优化得更好
对于性能要求高的产品代码,可以考虑用内联函数代替函数。
例外:
在日志记录场景中,需要通过函数式宏保持调用点的文件名(__FILE__)、行号(__LINE__)等信息。
例外:
在日志记录场景中,需要通过函数式宏保持调用点的文件名(__FILE__)、行号(__LINE__)等信息。
## <a name="c3-14"></a> 空格和空行
### <a name="r3-14-1"></a>规则3.14.1 水平空格应该突出关键字和重要信息,避免不必要的留白
...
...
@@ -647,19 +647,19 @@ int MyClass::GetValue() const {} // Good: 对于成员函数定义,不要留
// Good: 类的派生需要留有空格
class
Sub
:
public
Base
{
};
// 构造函数初始化列表需要留有空格
MyClass
::
MyClass
(
int
var
)
:
someVar_
(
var
)
MyClass
::
MyClass
(
int
var
)
:
someVar_
(
var
)
{
DoSomething
();
}
// 位域表示也留有空格
struct
XX
{
char
a
:
4
;
char
b
:
5
;
char
a
:
4
;
char
b
:
5
;
char
c
:
4
;
};
```
...
...
@@ -733,7 +733,7 @@ public: // 注意没有缩进
~
MyClass
()
{}
void
SomeFunction
();
void
SomeFunctionThatDoesNothing
()
void
SomeFunctionThatDoesNothing
()
{
}
...
...
@@ -754,7 +754,7 @@ private:
### <a name="r3-15-2"></a>规则3.15.2 构造函数初始化列表放在同一行或按四格缩进并排多行
```
cpp
// 如果所有变量能放在同一行:
MyClass
::
MyClass
(
int
var
)
:
someVar_
(
var
)
MyClass
::
MyClass
(
int
var
)
:
someVar_
(
var
)
{
DoSomething
();
}
...
...
@@ -770,28 +770,28 @@ MyClass::MyClass(int var)
// 如果初始化列表需要置于多行, 需要逐行对齐
MyClass
::
MyClass
(
int
var
)
:
someVar_
(
var
),
// 缩进4个空格
someOtherVar_
(
var
+
1
)
{
someOtherVar_
(
var
+
1
)
{
DoSomething
();
}
```
# <a name="c4"></a>4 注释
一般的,尽量通过清晰的架构逻辑,好的符号命名来提高代码可读性;需要的时候,才辅以注释说明。
一般的,尽量通过清晰的架构逻辑,好的符号命名来提高代码可读性;需要的时候,才辅以注释说明。
注释是为了帮助阅读者快速读懂代码,所以要从读者的角度出发,
**按需注释**
。
注释内容要简洁、明了、无二义性,信息全面且不冗余。
**注释跟代码一样重要。**
写注释时要换位思考,用注释去表达此时读者真正需要的信息。在代码的功能、意图层次上进行注释,即注释解释代码难以表达的意图,不要重复代码信息。
**注释跟代码一样重要。**
写注释时要换位思考,用注释去表达此时读者真正需要的信息。在代码的功能、意图层次上进行注释,即注释解释代码难以表达的意图,不要重复代码信息。
修改代码时,也要保证其相关注释的一致性。只改代码,不改注释是一种不文明行为,破坏了代码与注释的一致性,让阅读者迷惑、费解,甚至误解。
使用英文进行注释。
使用英文进行注释。
## <a name="c3-1"></a>注释风格
在 C++ 代码中,使用
`/*`
`*/`
和
`//`
都是可以的。
按注释的目的和位置,注释可分为不同的类型,如文件头注释、函数头注释、代码注释等等;
在 C++ 代码中,使用
`/*`
`*/`
和
`//`
都是可以的。
按注释的目的和位置,注释可分为不同的类型,如文件头注释、函数头注释、代码注释等等;
同一类型的注释应该保持统一的风格。
注意:本文示例代码中,大量使用 '//' 后置注释只是为了更精确的描述问题,并不代表这种注释风格更好。
...
...
@@ -948,7 +948,7 @@ const int ANOTHER_CONST = 200; /* 上下对齐时,与左侧代码保持间
示例:
```
cpp
// Foo.h
// Foo.h
#ifndef FOO_H
#define FOO_H
...
...
@@ -957,7 +957,7 @@ class Foo {
public:
Foo
();
void
Fun
();
private:
int
value_
;
};
...
...
@@ -985,7 +985,7 @@ void Foo::Fun()
## <a name="c5-2"></a> 头文件依赖
### <a name="r5-2-1"></a>规则5.2.1 禁止头文件循环依赖
头文件循环依赖,指 a.h 包含 b.h,b.h 包含 c.h,c.h 包含 a.h, 导致任何一个头文件修改,都导致所有包含了a.h/b.h/c.h的代码全部重新编译一遍。
头文件循环依赖,指 a.h 包含 b.h,b.h 包含 c.h,c.h 包含 a.h, 导致任何一个头文件修改,都导致所有包含了a.h/b.h/c.h的代码全部重新编译一遍。
而如果是单向依赖,如a.h包含b.h,b.h包含c.h,而c.h不包含任何头文件,则修改a.h不会导致包含了b.h/c.h的源代码重新编译。
头文件循环依赖直接体现了架构设计上的不合理,可通过优化架构去避免。
...
...
@@ -1018,7 +1018,7 @@ void Foo::Fun()
```
cpp
extern
int
Fun
();
// Bad: 通过extern的方式使用外部函数
void
Bar
()
void
Bar
()
{
int
i
=
Fun
();
...
...
...
@@ -1027,7 +1027,7 @@ void Bar()
// b.cpp内容
```
cpp
int
Fun
()
int
Fun
()
{
// Do something
}
...
...
@@ -1038,7 +1038,7 @@ int Fun()
```
cpp
#include "b.h" // Good: 通过包含头文件的方式使用其他.cpp提供的接口
void
Bar
()
void
Bar
()
{
int
i
=
Fun
();
...
...
...
@@ -1052,7 +1052,7 @@ int Fun();
// b.cpp内容
```
cpp
int
Fun
()
int
Fun
()
{
// Do something
}
...
...
@@ -1150,7 +1150,7 @@ namespace {
void
Foo
::
Fun
()
{
int
i
=
MAX_COUNT
;
InternalFun
();
}
...
...
@@ -1177,14 +1177,14 @@ using namespace NamespaceB;
void
G
()
{
Fun
(
1
);
Fun
(
1
);
}
```
```
cpp
// 源代码a.cpp
#include "a.h"
using
namespace
NamespaceA
;
using
namespace
NamespaceA
;
#include "b.h"
void
main
()
...
...
@@ -1267,12 +1267,12 @@ public:
static
Counter
counter
;
return
counter
;
}
// 单实例实现简单举例
void
Increase
()
void
Increase
()
{
value_
++
;
}
void
Print
()
const
{
std
::
cout
<<
value_
<<
std
::
endl
;
...
...
@@ -1305,7 +1305,7 @@ Counter::GetInstance().Print();
构造,拷贝,移动和析构函数提供了对象的生命周期管理方法:
-
构造函数(constructor):
`X()`
-
拷贝构造函数(copy constructor):
`X(const X&)`
-
拷贝赋值操作符(copy assignment):
`operator=(const X&)`
-
拷贝赋值操作符(copy assignment):
`operator=(const X&)`
-
移动构造函数(move constructor):
`X(X&&)`
*C++11以后提供*
-
移动赋值操作符(move assignment):
`operator=(X&&)`
*C++11以后提供*
-
析构函数(destructor):
`~X()`
...
...
@@ -1365,7 +1365,7 @@ public:
{
msgBuffer_
=
nullptr
;
// Bad,不推荐在构造函数中赋值
}
private:
unsigned
int
msgID_
{
0
};
// Good,C++11中使用
unsigned
int
msgLength_
;
...
...
@@ -1414,7 +1414,7 @@ private:
Foo
&
operator
=
(
const
Foo
&
);
};
```
2.
使用C++11提供的delete, 请参见后面现代C++的相关章节。
2.
使用C++11提供的delete, 请参见后面现代C++的相关章节。
3.
推荐继承NoCopyable、NoMovable,禁止使用DISALLOW_COPY_AND_MOVE,DISALLOW_COPY,DISALLOW_MOVE等宏。
...
...
@@ -1502,8 +1502,8 @@ public:
示例:类Base是基类,Sub是派生类
```
cpp
class
Base
{
public:
class
Base
{
public:
Base
();
virtual
void
Log
()
=
0
;
// 不同的派生类调用不同的日志文件
};
...
...
@@ -1511,11 +1511,11 @@ public:
Base
::
Base
()
// 基类构造函数
{
Log
();
// 调用虚函数Log
}
}
class
Sub
:
public
Base
{
class
Sub
:
public
Base
{
public:
virtual
void
Log
();
virtual
void
Log
();
};
```
...
...
@@ -1525,13 +1525,13 @@ public:
同样的道理也适用于析构函数。
### <a name="r7-1-7"></a>规则7.1.7 多态基类中的拷贝构造函数、拷贝赋值操作符、移动构造函数、移动赋值操作符必须为非public函数或者为delete函数
如果报一个派生类对象直接赋值给基类对象,会发生切片,只拷贝或者移动了基类部分,损害了多态行为。
如果报一个派生类对象直接赋值给基类对象,会发生切片,只拷贝或者移动了基类部分,损害了多态行为。
【反例】
如下代码中,基类没有定义拷贝构造函数或拷贝赋值操作符,编译器会自动生成这两个特殊成员函数,
如果派生类对象赋值给基类对象时就发生切片。可以将此例中的拷贝构造函数和拷贝赋值操作符声明为delete,编译器可检查出此类赋值行为。
```
cpp
class
Base
{
public:
class
Base
{
public:
Base
()
=
default
;
virtual
~
Base
()
=
default
;
...
...
...
@@ -1565,8 +1565,8 @@ Foo(d); // 传入的是派生类对象
class
Base
{
public:
virtual
std
::
string
getVersion
()
=
0
;
~
Base
()
~
Base
()
{
std
::
cout
<<
"~Base"
<<
std
::
endl
;
}
...
...
@@ -1577,15 +1577,15 @@ public:
class
Sub
:
public
Base
{
public:
Sub
()
:
numbers_
(
nullptr
)
{
{
}
~
Sub
()
{
delete
[]
numbers_
;
std
::
cout
<<
"~Sub"
<<
std
::
endl
;
}
int
Init
()
{
const
size_t
numberCount
=
100
;
...
...
@@ -1593,12 +1593,12 @@ public:
if
(
numbers_
==
nullptr
)
{
return
-
1
;
}
...
}
std
::
string
getVersion
()
{
std
::
string
getVersion
()
{
return
std
::
string
(
"hello!"
);
}
private:
...
...
@@ -1616,7 +1616,7 @@ int main(int argc, char* args[])
}
```
由于基类Base的析构函数没有声明为virtual,当对象被销毁时,只会调用基类的析构函数,不会调用派生类Sub的析构函数,导致内存泄漏。
例外:
例外:
NoCopyable、NoMovable这种没有任何行为,仅仅用来做标识符的类,可以不定义虚析构也不定义final。
### <a name="r7-2-2"></a>规则7.2.2 禁止虚函数使用缺省参数值
...
...
@@ -1629,7 +1629,7 @@ public:
{
std
::
cout
<<
text
<<
std
::
endl
;
}
virtual
~
Base
(){}
};
...
...
@@ -1637,9 +1637,9 @@ class Sub : public Base {
public:
virtual
void
Display
(
const
std
::
string
&
text
=
"Sub!"
)
{
std
::
cout
<<
text
<<
std
::
endl
;
std
::
cout
<<
text
<<
std
::
endl
;
}
virtual
~
Sub
(){}
};
...
...
@@ -1647,12 +1647,12 @@ int main()
{
Base
*
base
=
new
Sub
();
Sub
*
sub
=
new
Sub
();
...
base
->
Display
();
// 程序输出结果: Base! 而期望输出:Sub!
sub
->
Display
();
// 程序输出结果: Sub!
delete
base
;
delete
sub
;
return
0
;
...
...
@@ -1669,15 +1669,15 @@ public:
void
Fun
();
};
class
Sub
:
public
Base
{
class
Sub
:
public
Base
{
public:
void
Fun
();
};
Sub
*
sub
=
new
Sub
();
Sub
*
sub
=
new
Sub
();
Base
*
base
=
sub
;
sub
->
Fun
();
// 调用子类的Fun
sub
->
Fun
();
// 调用子类的Fun
base
->
Fun
();
// 调用父类的Fun
//...
...
...
@@ -1719,7 +1719,7 @@ class basic_istream {};
class
basic_ostream
{};
class
basic_iostream
:
public
basic_istream
,
public
basic_ostream
{
};
```
...
...
@@ -1894,7 +1894,7 @@ enum SessionState {
```
cpp
enum
RTCPType
{
RTCP_SR
=
200
,
RTCP_MIN_TYPE
=
RTCP_SR
,
RTCP_MIN_TYPE
=
RTCP_SR
,
RTCP_RR
=
201
,
RTCP_SDES
=
202
,
RTCP_BYE
=
203
,
...
...
@@ -1904,7 +1904,7 @@ enum RTCPType {
RTCP_XR
=
207
,
RTCP_RSI
=
208
,
RTCP_PUBPORTS
=
209
,
RTCP_MAX_TYPE
=
RTCP_PUBPORTS
RTCP_MAX_TYPE
=
RTCP_PUBPORTS
};
```
...
...
@@ -2006,7 +2006,7 @@ x = Func(i, i);
特例:
如果switch条件变量是枚举类型,并且 case 分支覆盖了所有取值,则加上default分支处理有些多余。
现代编译器都具备检查是否在switch语句中遗漏了某些枚举值的case分支的能力,会有相应的warning提示。
现代编译器都具备检查是否在switch语句中遗漏了某些枚举值的case分支的能力,会有相应的warning提示。
```
cpp
enum
Color
{
...
...
@@ -2031,11 +2031,11 @@ switch (color) {
应当按人的正常阅读、表达习惯,将常量放右边。写成如下方式:
```
cpp
if
(
value
==
MAX
)
{
}
if
(
value
<
MAX
)
{
}
```
也有特殊情况,如:
`if (MIN < value && value < MAX)`
用来描述区间时,前半段是常量在左的。
...
...
@@ -2102,7 +2102,7 @@ C++提供的类型转换操作比C风格更有针对性,更易读,也更加
```
cpp
// 不好的例子
const
int
i
=
1024
;
const
int
i
=
1024
;
int
*
p
=
const_cast
<
int
*>
(
&
i
);
*
p
=
2048
;
// 未定义行为
```
...
...
@@ -2113,7 +2113,7 @@ class Foo {
public:
Foo
()
:
i
(
3
)
{}
void
Fun
(
int
v
)
void
Fun
(
int
v
)
{
i
=
v
;
}
...
...
@@ -2180,12 +2180,12 @@ public:
{
lock_
.
Acquire
();
}
~
LockGuard
()
{
lock_
.
Release
();
}
private:
LockType
lock_
;
};
...
...
@@ -2199,7 +2199,7 @@ bool Update()
}
else
{
// 操作数据
}
return
true
;
}
```
...
...
@@ -2317,7 +2317,7 @@ class Foo {
public:
Foo
(
int
length
)
:
dataLength_
(
length
)
{}
private:
const
int
dataLength_
;
const
int
dataLength_
;
};
```
...
...
@@ -2385,18 +2385,18 @@ C++提供了强大的泛型编程的机制,能够实现非常灵活简洁的
4.
模板如果使用不当,会导致运行时代码过度膨胀。
5.
模板代码难以修改和重构。模板的代码会在很多上下文里面扩展开来, 所以很难确认重构对所有的这些展开的代码有用。
所以,OpenHarmony大部分部件禁止模板编程,仅有 __少数部件__ 可以使用泛型编程,并且开发的模板要有详细的注释。
例外:
所以,OpenHarmony大部分部件禁止模板编程,仅有 __少数部件__ 可以使用泛型编程,并且开发的模板要有详细的注释。
例外:
1.
stl适配层可以使用模板
## <a name="c9-9"></a> 宏
在C++语言中,我们强烈建议尽可能少使用复杂的宏
-
对于常量定义,请按照前面章节所述,使用const或者枚举;
-
对于常量定义,请按照前面章节所述,使用const或者枚举;
-
对于宏函数,尽可能简单,并且遵循下面的原则,并且优先使用内联函数,模板函数等进行替换。
```
cpp
// 不推荐使用宏函数
#define SQUARE(a, b) ((a) * (b))
#define SQUARE(a, b) ((a) * (b))
// 请使用模板函数,内联函数等来替换。
template
<
typename
T
>
T
Square
(
T
a
,
T
b
)
{
return
a
*
b
;
}
...
...
@@ -2655,7 +2655,7 @@ void func()
**理由**
智能指针会自动释放对象资源避免资源泄露,但会带额外的资源开销。如:智能指针自动生成的类、构造和析构的开销、内存占用多等。
单例、类的成员等对象的所有权不会被多方持有的情况,仅在类析构中释放资源即可。不应该使用智能指针增加额外的开销。
单例、类的成员等对象的所有权不会被多方持有的情况,仅在类析构中释放资源即可。不应该使用智能指针增加额外的开销。
**示例**
...
...
@@ -2664,7 +2664,7 @@ class Foo;
class
Base
{
public:
Base
()
{}
virtual
~
Base
()
virtual
~
Base
()
{
delete
foo_
;
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录