C++ Coding & Debug 经验分享

Jianbing Fang

2021.02.02

范围定位

代码走查

修复验证

BUG 预防

“不治已病治未病”

C++ 的锅 我的锅 别人的锅
代码逻辑
内存管理
性能问题
设计缺陷

代码逻辑

  • Test
    • ​normal & abnormal
    • compatibility
  • Code Review
    • ​self review
    • peer review
  • 可读性第一
    • 命名 🏅
    • 写有用的 LOG
    • ​长逻辑拆分
    • 分层抽象
    • 不给别人犯错的机会 🏅
int row = 0;
int missing_cnt = 0;
std::for_each(begin, end, [&](const auto &result) {
  auto attr_dict_api = interop::WrapItemAttrAsAttrDictApi(context, result.item_key);
  auto *attr = attr_dict_api->Lookup(input_config.attr_name);
  if (attr) {
    FillMatrixRow(attr, input->value_view(), row++, input_config.dim, context);
  } else {
    ++missing_cnt;
  }
});
int row = 0;
int missing_cnt = 0;
std::for_each(begin, end, [&](const auto &result) {
  auto attr_dict_api = interop::WrapItemAttrAsAttrDictApi(context, result.item_key);
  auto *attr = attr_dict_api->Lookup(input_config.attr_name);
  if (attr) {
    FillMatrixRow(attr, input->value_view(), row, input_config.dim, context);
  } else {
    ++missing_cnt;
  }
  row++;
});

phab: D105874

// 👎
int v = *p++;
// 👍
int v = *(p++);

// 👎
for (int i = 0; i < item_list.size(); ++i) {
  const auto &item = item_list[i];
  // do something with item
}
// 👍
for (const auto &item : item_list) {
  // do something with item
}

// 👎
for (auto obj : some_list) {
  // do something with obj
}
// 👍
for (auto &obj : some_list) {
  // do something with obj
}

// 👎
class Abc {
 private:
  int count_;
  const double *ptr_;
};
// 👍
class Abc {
 private:
  int count_ = 0;
  const double *ptr_ = nullptr;
};

More Tips

  • 熟知 STL 和各类 util
  • 善用 () 和 {}
  • 小心下标操作
  • 注意拷贝和引用
  • 定义变量初始值
  • RAII
  • 勤做微重构
  • 少写代码
  • 多看代码
  • sonar

内存管理

C++ 垃圾回收

Java 垃圾回收

小心指针!

  • 优先使用栈空间分配
  • 优先使用 unique_ptr
  • 搞清每一个裸指针的所有权
ConstArray<double> double_list;
std::string payload = GetData();
double_list.SetData(payload);
for (auto val : double_list) {
  std::cout << val << "\n";
}
ConstArray<double> double_list;

double_list.SetData(GetData());
for (auto val : double_list) {
  std::cout << val << "\n";
}
template <typename T>
struct ConstArray {
  const T *list = nullptr;
  int size = 0;

  void SetData(const char *data, int data_size) {
    if (data_size % sizeof(T) == 0) {
      list = reinterpret_cast<const T *>(data);
      size = data_size / sizeof(T);
    } else {
      list = nullptr;
      size = 0;
    }
  }

  void SetData(const std::string &data) { SetData(data.data(), data.size()); }
}

你能找出这段代码的 bug 吗?

正确的实现

小心容器!

  • 哪些是容器?
  • 容器的扩容规则?
  • 容器空间会无限增大吗?
std::vector<std::string> str_list;
for (int i = 0; i < 1'000'000; ++i) {
  str_list.push_back(std::to_string(i));
}

VS

std::vector<std::string *> str_list;
for (int i = 0; i < 1'000'000; ++i) {
  auto *p = new std::string(std::to_string(i));
  str_list.push_back(p);
}
std::vector<ProtobufMessage> str_list;
for (int i = 0; i < 1'000'000; ++i) {
  str_list.push_back(ProtobufMessage());
}

VS

std::vector<ProtobufMessage *> str_list;
for (int i = 0; i < 1'000'000; ++i) {
  auto *p = new ProtobufMessage();
  str_list.push_back(p);
}
thread_local ProtobufMessage msg;
msg.Clear();
msg.ParseFromString(payload);

VS

ProtobufMessage msg;
msg.ParseFromString(payload);
void Handle(const std::vector<int *> &list);

void Calculate(std::vector<int> *data) {
  if (!data) return;
  const int size = 100;
  data->reserve(size);
  std::vector<int *> addr_list;
  for (int i = 0; i < size; ++i) {
    data->push_back(i);
    int *p = &(data->back());
    addr_list.push_back(p);
  }
  Handle(addr_list);
}

找找这段代码的 bug?

范围定位

代码走查

修复验证

  • C++ 基本功
  • 缜密的思维
  • 计算机系统综合理论

范围定位

代码走查

修复验证

  • C++ 基本功
  • 缜密的思维
  • 计算机系统综合理论

Core 问题

GDB

  • bt (backtrace)

  • p (print)

addr2line

  • addr2line -f -e EXECUTABLE Address

运行 diag_opt 版本 🤔

性能问题

把系统做透明

那些你可能会忽视的点

  • 磁盘 IO: LOG / dump
  • perflog
  • hash 计算
std::unordered_map<std::string, int> total_count;
std::unordered_map<std::string, int> succ_count;
for (const auto &item : items) {
  for (const auto &attr : attrs) {
    if (item.HasAttr(attr)) {
      ++succ_count[attr];
    }
    ++total_count[attr];
  }
}
std::unordered_map<std::string, std::pair<int, int>> count;
for (const auto &attr : attrs) {
  auto &pr = count[attr];
  for (const auto &item : items) {
    if (item.HasAttr(attr)) {
      ++pr.second;
    }
    ++pr.first;
  }
}
std::vector<std::pair<int, int>> count;
count.resize(attrs.size());
for (int i = 0; i < attrs.size(); ++i) {
  const auto &attr = attrs[i];
  auto &pr = count[i];
  for (const auto &item : items) {
    if (item.HasAttr(attr)) {
      ++pr.second;
    }
    ++pr.first;
  }
}

内存检测工具:kperf

万金油:diff 二分查找

范围定位

代码走查

修复验证

  • backtrace
  • kperf
  • 服务监控
  • 回查工具
  • diff 二分查找
  • LOG / print
  • C++ 基本功
  • 缜密的思维
  • 计算机系统综合理论

范围定位

代码走查

修复验证

  • C++ 基本功
  • 缜密的思维
  • 计算机系统综合理论
  • backtrace
  • kperf
  • 服务监控
  • 回查工具
  • diff 二分查找
  • LOG / print
  • 交叉验证
  • 小心引入新 bug

范围定位

代码走查

修复验证

  • C++ 基本功
  • 缜密的思维
  • 计算机系统综合理论
  • backtrace
  • kperf
  • 服务监控
  • 回查工具
  • diff 二分查找
  • LOG / print
  • 交叉验证
  • 小心引入新 bug

Thanks

没内存条还想写 C++?

全新

金士顿

32G

3200Mhz

内存条

京东 1079

现一口价

只要

799 !!!

C++ Coding & Debug 经验分享

By Jesse Fang

C++ Coding & Debug 经验分享

  • 159