简介
给策略同学过c++代码时,总结了一些问题,包括三类
- 避免影响性能的问题
- 避免宕机问题
- 避免丑陋代码和不标准的格式 本文介绍下CR中遇到的各种具体问题
避免影响性能
避免容器里的重复查找
看这段代码,假设map_
是std::map
,下面这段代码在map_里搜索了两次,第一次是find()
,第二次是map_[id]
,这里犯了重复查找的问题
if (map_.find(id) != map_.end()) {
map_[id]++;
}
把find()
的结果保存下来,避免第二次查找,改成下面这样:
auto it = map_.find(id)
if (it != map_.end()) {
*it++;
}
修改后的代码就只有find()
的时候查找了一次
注意要求对方在for循环中使用const和引用
for (auto iter : dict())
如果不改变元素,需要改成
for (const auto & conf : dict())
使用现成容器函数
现成的容器函数往往能替换掉大段的 for循环 + if判断
常用的有:
find_if()
count_if()
boost::range::remove_erase_if
具体使用见这篇文章
避免无用的深拷贝
避免无用的深拷贝,当声明一个类对象时,例如
std::string s2 = s1;
这个属于高频问题,看到非基础类型的定义时就应该虎躯一震,看看这里是不是用引用就行。许多c++开发经验的同学都是完全没有这个意识的
std::string& s2 = s1;
避免宕机
在已有循环中添加代码,注意break,continue
已经有一大段循环的代码,当别人往里面添加逻辑时,要注意他加入的break
,continue
,return
语句是否合理,后面有没有必须要走的逻辑,被他这句break
跳过就完蛋了,比如下面代码,加的break
会破坏后面的重要逻辑L。
所以遇到这种代码,要展开看一下后续逻辑,不要只看新增的代码
for (...){
// 一堆代码...
**在这增加代码**
if (xxx){break;}
// 一堆代码...
// 重要逻辑L
}
看到除号,注意除0判断
CR的时候看到除号
要下意识看看分母有没有可能为0,有没有做除0判断
注意下标越界
- 对map取下标
map[key]
,要注意这个key
是否一定存在,不存在的话加没加map.find(key)==map.end()
判断 - 对数组取下标,例如
vector[index]
,要注意index是否为负数或者>=size
编码规范&&美化代码
注意临时变量是否有用到,或者函数中有无用变量
有时候声明一个变量却没有用到,或者对他一通操作,但是函数返回值跟这个无关,这属于无用的变量,需要避免
简化大段的 if else 嵌套
直接看代码吧:
while (!query_vec.empty()) {
std::string query = query_vec.back();
if (flag_) {
if (boost::starts_with(query, "#") && boost::ends_with(query, "#")) {
query_vec.pop_back();
continue;
} else {
info_vec.push_back(query);
}
} else {
info_vec.push_back(query);
}
query_vec.pop_back();
}
上面这段代码及其丑陋,读起来太难受了 简化下来的代码如下:
while (!user_search_querys_vec.empty()) {
std::string query = query_vec.back();
if (!flag_
|| (flag_
&& boost::starts_with(query, "#")
&& boost::ends_with(query, "#")) {
info_vec.push_back(query);
}
query_vec.pop_back();
}
好看多了吧。。。
容易忽略的BUG
慎用Fa() && Fb();
以下代码需要注意的是,如果Fa()返回false,Fb就不会执行了,这么写之前你需要考虑清楚,Fa失败的情况下你想不想让Fb仍然执行
bool F() {
return Fa()&&Fb();
}
使用std::function时,function中的参数要注意是传值还是引用
例如以下代码:
class ClassWithMap {
public:
bool Visit(std::function<bool(std::unordered_map<int, int>&)>&& fun) {
fun(map_);
}
private:
std::unordered_map<int, int> map_;
};
int main () {
ClassWithMap class_with_map;
auto fun = [&](std::unordered_map<int, int> m) {
m.emplace(1,1);
};
class_with_map.visit(std::move(fun)); // 想要用fun对class_with_map中map_里的值做一些修改
return 0;
}
上面这段代码,可以看到fun的类型是std::function<bool(std::unordered_map<int, int>)>,是传值的,调用visit并不能修改class_with_map中的值,但是这段代码仍然能过通过编译,因为std::function构造函数接收的类型广泛,如果想要在编译时报错,可以加入下面这句禁用掉传值调用
bool Visit(std::function<bool(std::unordered_map<int, int>)>&& fun) = delete;