用C++核心指南检查器检查是否正确

这篇博文是由Sunny Chatterjee和Andrew Pardoe撰写的

null

这个 C++核心指南 专注于提高代码正确性和安全性的简单方法。我们介绍了 C++核心指南检查器 帮助实现代码中C++核心指南的自动化。

对代码所做的最简单也是最重要的更改之一是将不可变数据标记为“const”。不是我们和核心指导方针相信:看到了吗 这篇精彩的博文 从布鲁斯道森关于增加 const 你的代码(他在MSVC上也提到了这一点 正在删除 const 可以使一些代码更快,但这反映了一个编译器错误,我们正在修复感谢布鲁斯的反馈。)因为 const 非常重要的是,我们添加了一个新的C++核心指导检查程序。 const 正确性。

我们在C++核心准则检查器中创建了四个新规则,这些规则覆盖了当前包含在 常数与不变性 C++核心指南的一节。实际上,我们并没有为所有规则添加这些检查,我们实现了对规则2的检查,“默认情况下,生成成员函数 const “但是删除了它,因为它在有效代码上引发了太多误报。请参阅下面的详细信息。此外,该工具不会警告您可以将存根函数标记为 const 因为我们知道你可能会把 const 稍后当您实现该函数时。

常量检查器规则

Con.1:默认情况下,使对象不可变

这条规则是一个总的想法,说明我们应该始终将对象标记为 const 除非我们写信给他们。我们通过在检查器中更具体地实现后续规则来覆盖此规则。

Con.3:默认情况下,将指针和引用传递给 常数

我们的检查人员执行这个规则。您可以传递指向非常量对象的指针或引用,但如果这样做,调用者将假定其参数将被修改。如果函数没有修改对象,我们应该将对象标记为const以使意图显式。

此支票的优点
  • 使被调用者的意图向调用者明确表示是否修改参数。
  • 函数体中的未来修改不会改变调用者的期望。

我们使用某些启发式方法来减少噪音-

  • 我们不要求将通过值传递的参数或指针参数本身标记为 const .
  • 我们不要求将未使用的参数标记为 const 因为我们没有足够的信息来了解他们的意图。
  • 我们不在虚拟函数上强制执行此操作,因为作者可能希望遵循特定的派生行为。
示例
// Expect 26461: The input pointer argument b in function f7 can be marked as constint f7(const int *a, int *b){    return *a + *b;}struct S0{    virtual void m();};// Expect 26461 on 'p' but don't report on unnamed parameter.S0 f8(int *p, int *){    (p == nullptr);    // Don't report on return UDT.    return{};}

Con.4:使用 常数 使用构造后不会更改的值定义对象的步骤

我们的检查人员执行这个规则。它类似于con.3,但适用于所有变量,而不仅仅是指针或引用参数。它有助于防止意外的对象值更改。

这种检查的优点与con.3非常相似
  • 如果我们知道一个对象在声明点是否是不可变的,就更容易对代码进行推理。
  • 以后对代码的修改不能更改对象的不可变属性。

像con.3一样,我们使用某些启发式方法来减少噪音-

  • 我们避免在未使用的变量上使用const–它们很少添加任何值。
  • 我们不建议将指针或引用本身标记为 const ,因为用户主要关心他们所指向的数据。
示例
int f5(){    // Expect 26496: Variable m is assigned only once, use const.    int m = 5;    const int a = 10;    if (m > a)        return m;    return a;}

Con.5:使用 常量表达式 对于可在编译时计算的值 F.4:如果一个函数可能需要在编译时进行求值,那么声明它 常量表达式

我们的检查器鼓励程序员将编译时可能需要计算的函数声明为 constexpr .

示例
// Expect 26497: could be marked constexpr if compile-time evaluation is desiredint f1(int a, int b){    return a + b;}constexpr int f2(int a, int b){    return a + b;}void f3(){   // Compile-time evaluation    constexpr int m = f2(10, 20);        // Expect 26498: This function call f2 can use constexpr if compile-time evaluation is desired.    const int m2 = f2(10, 20);}

规则2:我们没有包括的那个

Con.2:默认情况下,生成成员函数 常数

在最初的原型中,我们包含了这个检查。但是,在对一些实际代码运行此检查之后,我们决定将其从checker的发布版本中删除。我们不希望程序员将其成员函数标记为 const 当他们在逻辑上是非- const . 对于无畏者,在isocpp.org网页上有一个关于逻辑和物理常数的讨论: https://isocpp.org/wiki/faq/const-correctness#logical-vs物理状态 .

下面是一个示例,其中成员函数在逻辑上是非常量的。你可以标记成员函数 bar 作为 const ,例如。, void bar() const { *data_  = GetData(); } . 但它不会改变指针 data_ 它本身可以改变 data_ . 因此,这个函数在逻辑上是不正确的 const .

class Test{public:    // This method should be marked “const” since it doesn’t change the logical state of the object.    MyData foo() const { return *data_; }         // This method shouldn’t be blindly marked as “const”. It doesn’t alter the pointer data_ itself.    // However, it alters the state of memory pointed-to by it.    void bar() const { *data_ = GetData(); }private:    // data_ is a pointer to a “MyData” object    MyData *data_;};

将您的反馈发送给我们!

一如既往,我们欢迎您的反馈。对于问题,请通过“报告问题”选项通知我们,无论是从安装程序还是VisualStudioIDE本身 用户语音 . 您随时可以通过电子邮件联系我们cppcorecheck@microsoft.com.

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享