静态成员变量的 C++ 核心指南

C++ Core Guidelines for static member variables

我的 class 中有一个私有静态向量,它保留指向从它创建的所有对象的指针。这是必要的,因为每个对象都需要访问所有其他对象的信息来执行一些计算:

// Header file:
class Example {
public:
    Example();
private:
    static std::vector<const Example*> examples_;
};
// Cpp file:
std::vector<const Example *> Example::examples_ = {};
Example::Example() {
    // intialization
    examples_.emplace_back(this);
}
void Example::DoCalc() {
    for (auto example : examples_) {
        // do stuff
    }
}

clang-tidy 指出我违反了 C++ 核心指南,即:“变量 'examples_' 是非常量且全局可访问的,考虑将其设为常量 (cppcoreguidelines-avoid-non-const-global-variables)” .

就我个人而言,我看不出我的代码与核心指南中的示例代码有何相似之处,尤其是因为该变量位于 class 内部并且是私有的。 'correct' 实现此功能的方法是什么?如果可以避免,我不想从 clang-tidy 中禁用此检查。

Personally, I don't see the resemblance between my code and the sample code in the core guidelines

您有一个变量可供每个线程访问,对 Example 的用户隐藏。与普通全局变量的唯一区别是它是 private,即你不能使用 name Example::examples_ 在 [=10 之外引用它=].

Note

The rule is "avoid", not "don't use."

实现此功能的“正确”方式可能是您拥有它的方式,但我强烈建议您修改“每个对象都需要访问所有其他对象的信息以执行某些计算”,以便您传递 std::vector<const Example*> 到需要的地方,跟踪所有相关的(尤其是活着的)Example 使用它们的地方。

Alternative: [...] Another solution is to define the data as the state of some object and the operations as member functions.

Warning: Beware of data races: If one thread can access non-local data (or data passed by reference) while another thread executes the callee, we can have a data race. Every pointer or reference to mutable data is a potential data race.

你做的很好。这就是class-static的字面意思。有些人会出于不相关的原因推荐替代方案,这可能值得考虑……但不是因为 clang-tidy 在这里告诉你的任何事情。

您 运行 clang-tidy bug #48040。您可以看到这一点,因为它的消息传递错误:向量是 not“全局可访问”,至少在访问规则的意义上不是,因为它被标记为 private(尽管它在全球范围内跨翻译单元存在,这很好。

您的代码与引用的核心指南不相关。

一个可能的解决方案是强制每个访问 Example::examples_ 的客户端通过一个函数。然后将 examples 作为静态变量放入该函数中。这样,将在第一次调用函数时创建对象 - 独立于任何全局对象构造顺序。

// Header file:
class Example {
public:
    Example();
private:
    std::vector<const Example*>& examples();
};
// Cpp file:
std::vector<Example *>& Example::examples()
{
    static std::vector<Example *> examples_;
    return examples_;
};
Example::Example() {
    // intialization
    examples().emplace_back(this);
}
void Example::DoCalc() {
    for (auto example : examples()) {
        // do stuff
    }
}

当然,如果您确定全局对象没有问题,并且确定在其构造期间没有其他全局对象正在访问Examples::examples_,则可以忽略该警告。这只是一个准则,您无需严格遵守。

正如 Asteroids With Wings 指出的那样,准则 I.2 不适用于您的代码。但请注意,CoreGuidelines 也打算禁止静态成员,请参阅 To-do: Unclassified proto-rules:

avoid static class members variables (race conditions, almost-global variables)