由C++原作者发起的一个modern C++ guidelilne. 在这里,配套的github页面在这里。
CppCoreGuidelines 配套一组 Guideline Support Library,源码位于这里。
我只记录了对自己有启发的内容。笔记中的大部分代码片段是复制于原文,我自己增加的代码片段会标注清楚。
class Date {
public:
Month month() const; // do
int month(); // don't
// ...
};
所以,推荐的做法是利用type对所有可能的概念进行建模。例如不用一个primitive类型int来表示月份,而用一个专门的Month类。但是这样做需要实现Month的一些运算用的接口,例如加法,减法。
change_speed(Speed s); // better: the meaning of s is specified
// ...
change_speed(2.3); // error: no unit
change_speed(23m / 10s); // meters per second
这里推荐我们实际使用value literal,也就是像23m,10s一样的实现。
使用gsl::index
而不是int
。
我理解的是在一段scope的开始,或者开始阶段,最好能够尽可能的指明接下来一段scope要进行的事。
不推荐的示例->
gsl::index i = 0;
while (i < v.size()) {
// ... do something with v[i] ...
}
原文认为i
在scope外,没有必要。只看while
的开头部分,没有对接下来要发生的循环提供更多信息。循环是为了做和v无关的事,还是要访问v,修改v?下面的代码有略微清楚的intent:我们要访问v中的所有元素,但不修改这些元素。
推荐的示例->
for (const auto& x : v) { /* do something with the value of x */ }
也可以尝试使用for_each
对于参数列表,有点类似于 P.1 ,定义专门的类。
draw_line(int, int, int, int); // obscure
draw_line(Point, Point); // clearer
原文强调,如果发生如下情况,很可能是函数设计的不够好。
functions with many parameters of built-in types
使用gsl中的span
来代替指针和size的组合。
void read(span<int> r); // read into the range of integers r
int a[100];
read(a); // better: let the compiler figure out the number of elements
extern void f4(vector<int>&); // separately compiled, possibly dynamically loaded
extern void f4(span<int>); // separately compiled, possibly dynamically loaded
// NB: this assumes the calling code is ABI-compatible, using a
// compatible C++ compiler and the same stdlib implementation
void g3(int n)
{
vector<int> v(n);
f4(v); // pass a reference, retain ownership
f4(span<int>{v}); // pass a view, retain ownership
}
原文说上述示例至少让f4有check范围(size or boundness)的可能。
下面代码是两个例子拼成的。
void increment2(span<int> p)
{
for (int& x : p) ++x;
}
void use3(int m)
{
const int n = 10;
int a[n] = {};
// ...
increment2(a); // the number of elements of a need not be repeated
// ...
}
此时increment2有能力进行范围检查,use3不会因为混淆n和m造成问题。
这里的示例没有解释特别细致。我理解到的指导意见是需要local copy时,尽量不要使用new delete pair,这在其他guideline里也有提到。但是这并不是因为效率问题,应该是为了防止leak。原文提到了struct内部变量声明的次序会引起空间浪费,这个在以前看到过但是并不记得正确的处理方法,一下也查不到其他guideline。
不要像下述代码片段一样在for循环中使用类似size()
的函数除非size()
真的会返回变化的数值。
void lower(zstring s)
{
for (int i = 0; i < strlen(s); ++i) s[i] = tolower(s[i]);
}