Skip to content

Commit

Permalink
添加一些注意事项
Browse files Browse the repository at this point in the history
  • Loading branch information
ShujiaHuang committed Jan 5, 2022
1 parent a15e2b1 commit 8b73d14
Showing 1 changed file with 107 additions and 0 deletions.
107 changes: 107 additions & 0 deletions practice/warnings.md
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



0 comments on commit 8b73d14

Please sign in to comment.