forked from ShujiaHuang/Cpp-Primer-Plus-6th
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a15e2b1
commit 8b73d14
Showing
1 changed file
with
107 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
# 本文档记录 C++ 编程过程中需要特别注意的事项 | ||
|
||
## 基础 | ||
|
||
1. 尽量用 `//` 而不是用 `/**/` 进行注释。 | ||
|
||
注释用 `/**/`,可能会出问题。原因是 `utf-8` 和 `ANSC(GB2312)` 编码混乱后,中文注释就乱码了, | ||
乱码中藏着 `*/`,匹配错了,导致 IDE 实际注释的部分并非肉眼所见,定位极其困难,常见于Windows中。 | ||
|
||
|
||
2. 如果要用 `std::sort()` 排序尽量对索引或者指针 `sort`,而不是针对对象本身,因为如果对象比较大,交换(复制)对象比交换指针或索引更耗费时间和资源。 | ||
|
||
3. 永不停歇的循环问题 | ||
|
||
```cpp | ||
for (unsigned int i = 5; i >=0; --i) | ||
{ | ||
//... | ||
} | ||
``` | ||
|
||
这个循环体是不会停下来的,因为 `unsigned int` 的变量强制永远 `≥0`。 | ||
|
||
```cpp | ||
std::vector<int> vec; | ||
vec.push_back(1); | ||
for (auto idx = vec.size(); idx >= 0; idx--) { | ||
//... | ||
} | ||
``` | ||
|
||
容器的 `size()` 返回类型是无符号整数,所以这个例子也一样会出现死循环,要特别注意。 | ||
|
||
|
||
4. 对于整型变量,应该更多地使用 `int` 或 `long` | ||
|
||
绝大多数情况下,用 `int`,`long` 就很好,`long` 一般等于机器字长,能直接放到寄存器,硬件处理起来速度也通常更快。 | ||
|
||
我们希望用 `short`, `char` 达到减少结构体大小的目的。但是由于字节对齐的原因,可能并不能真正减少大小,而且1,2个字节的整型位数太少,一不小心就溢出了,需要特别注意。除非我们需要面对存储大小非常敏感的场景,比如网络之类的。 | ||
|
||
局部变量更没有必要用(unsigned) short,char等,栈是自动伸缩的,它既不节省空间,还危险,还慢。 | ||
|
||
5. 浮点数判断是否相等问题 (**这个问题要再验证一下,好像不是这样了**) | ||
|
||
```cpp | ||
float f; | ||
if (f == 0.2) {} // 错误用法 | ||
|
||
if (abs(f - 0.2) < 0.00001) {} // 正确用法 | ||
|
||
``` | ||
|
||
|
||
## 指针与动态内存分配 | ||
|
||
1. 动态内存分配时,`malloc`-`free` 和 `new`-`delete` 应各自搭对编写。最大程度避免使用完内存之后,出现忘记归还给操作系统,导致内存泄露的情况。 | ||
|
||
2. `free` 或 `delete` 之后,相应指针必须立刻设置为 `NULL`,否则原指针就成了一个**野指针**,它所指向的内容将是无法预料的。 | ||
|
||
3. 指针在被定义的同时,就应该立刻初始化,或者直接初始化为 `NULL`。 | ||
|
||
4. 不用使用 `NULL` 指针 | ||
|
||
在使用内存分配函数分配内存的时候,应该用 `if(p==NULL)` 或 `if(p!=NULL)` 进行防错处理。 | ||
对于含有指针参数的函数,也应当在函数入口处用 `if(p==NULL)` 或 `if(p!=NULL)` 进行防错处理。 | ||
|
||
## 类 | ||
|
||
2. 不要在构造函数中再次调用构造函数 | ||
|
||
由于你再次调用的构造函数在原来的构造函数中是局部函数,所以再次调用的构造函数的所有的量可能都是局部变量,它在生命周期结束时,会面临被析构的危险,所以再次使用时就可能是垃圾值。 | ||
|
||
|
||
## C++ STL标准库 | ||
|
||
### vector | ||
|
||
1. 关于如何用 `vector` 存储对象值得注意的地方。 | ||
|
||
`vector` 是以 2 的次方动态扩容,并且为了确保数据保存在连续空间,每次扩充,都会将原成员悉数拷贝到新的内存块;所以不宜存大的对象(object),否则扩容会导致所有成员调用拷贝构造函数,消耗较大,一个更好的方法是保存对象的指针。 | ||
|
||
2. `resize()` 是重置大小;`reserve()` 是预留空间,并未改变 `size()`,可避免多次扩容;`clear()` 并不会导致空间收缩 ,如果需要释放空间,可以跟空的 `vector` 交换,`std::vector.swap(v)`,c++11里 `shrink_to_fit()` 也能收缩内存。 | ||
|
||
可以参考这个例子: https://blog.csdn.net/saibaobaodaren/article/details/108061765 | ||
|
||
3. 清空某个 `vector`,可以使用 `swap` 而不是其 `clear` 方法。 | ||
|
||
```cpp | ||
vector<int> vec; | ||
vector<int>().swap(vec); // 和一个空 vector 交换内容 | ||
vec.clear(); | ||
``` | ||
|
||
4. 理解 `at()` 和 `operator[]` 的区别 | ||
`at()` 会做下标越界检查,`operator[]` 提供数组索引级的访问,在 `release` 版本中不会进行下标越界检查,VC会在Debug版本会检查. | ||
|
||
**c++标准规定: `operator[]` 不提供下标安全性检查**。 | ||
|
||
5. C++标准规定了 `std::vector` 的底层是用数组来实现的。 | ||
|
||
6. 尽量不要在 `vector` 中存放 `bool` 类型,`vector` 为了做优化,它的内部存放的其实不是 `bool`。 | ||
|
||
### list | ||
### map | ||
|
||
|
||
|