静态成员变量的 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)
我的 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)