c++ - static 关键字及其在 C++ 中的各种用途

标签 c++ static

关键字 static 是一个在 C++ 中有多种含义的关键字,我发现它非常困惑,我永远无法理解它实际应该如何工作。

据我了解,有 static 存储持续时间,这意味着在全局情况下它会持续整个程序的生命周期,但是当您谈论局部时,这意味着默认情况下它是零初始化的。

C++ 标准对带有关键字 static 的类数据成员这样说:

3.7.1 静态存储时长[basic.stc.static]

3 The keyword static can be used to declare a local variable with static storage duration.

4 The keyword static applied to a class data member in a class definition gives the data member static storage duration.

局部变量是什么意思?那是函数局部变量吗?因为还有就是当你声明一个函数局部为static时,它只初始化一次,第一次进入这个函数。

它也只讨论关于类成员的存储持续时间,它是非实例特定的,这也是 static 的属性不是吗?还是存储期限?

现在 static 和文件范围的情况呢?默认情况下是否所有全局变量都被认为具有静态存储持续时间?以下(来自第 3.7.1 节)似乎表明了这一点:

1 All variables which do not have dynamic storage duration, do not have thread storage duration, and are not local have static storage duration. The storage for these entities shall last for the duration of the program (3.6.2, 3.6.3)

static 与变量的链接有什么关系?

整个 static 关键字完全令人困惑,有人可以用英语阐明它的不同用途,并告诉我何时初始化 static类(class)成员?

最佳答案

变量:

static 变量在其定义的翻译单元的“生命周期”内存在,并且:

  • 如果它在命名空间范围内(即在函数和类之外),则无法从任何其他翻译单元访问它。这被称为“内部链接”或“静态存储持续时间”。 (除了 constexpr 之外,不要在 header 中执行此操作。否则,您最终会在每个翻译单元中使用一个单独的变量,这非常令人困惑)
  • 如果它是函数中的变量,则无法从函数外部访问它,就像任何其他局部变量一样。 (这是他们提到的本地)
  • 由于 static,类成员没有限制范围,但可以从类和实例中寻址(如 std::string::npos)。 [注意:您可以在类中声明静态成员,但它们通常仍应在翻译单元(cpp 文件)中定义,因此,每个成员只有一个类]

位置代码:

static std::string namespaceScope = "Hello";
void foo() {
    static std::string functionScope= "World";
}
struct A {
   static std::string classScope = "!";
};

在执行翻译单元中的任何函数之前(可能在 main 开始执行之后),该翻译单元中具有静态存储持续时间(命名空间范围)的变量将被“常量初始化”(到 constexpr 在可能的情况下,否则为零),然后非局部变量按照它们在翻译单元中定义的顺序正确地“动态初始化”(对于 std::string="HI"; 不是 constexpr)。最后,函数局部静态将在第一次执行“到达”声明它们的行时被初始化。所有 static 变量都按照初始化的相反顺序销毁。

获得所有这些权利的最简单方法是将所有不是 constexpr 的静态变量初始化为函数静态局部变量,这确保在您尝试时正确初始化所有静态变量/全局变量无论如何都要使用它们,从而防止 static initialization order fiasco .

T& get_global() {
    static T global = initial_value();
    return global;
}

小心,因为当规范说 namespace 范围变量默认具有“静态存储持续时间”时,它们的意思是“翻译单元的生命周期”位,但这并不意味着它可以' 在文件外部访问。

函数

明显更直接的是,static 通常用作类成员函数,很少用于独立函数。

静态成员函数与常规成员函数的不同之处在于,它可以在没有类实例的情况下被调用,并且由于它没有实例,它不能访问类的非静态成员。当您想要一个绝对不引用任何实例成员的类的函数或管理 static 成员变量时,静态变量很有用。

struct A {
    A() {++A_count;}
    A(const A&) {++A_count;}
    A(A&&) {++A_count;}
    ~A() {--A_count;}

    static int get_count() {return A_count;}
private:
    static int A_count;
}

int main() {
    A var;

    int c0 = var.get_count(); //some compilers give a warning, but it's ok.
    int c1 = A::get_count(); //normal way
}

static 自由函数意味着该函数不会被任何其他翻译单元引用,因此链接器可以完全忽略它。这有几个目的:

  • 可以在 cpp 文件中使用,以保证永远不会在任何其他文件中使用该函数。
  • 可以放在标题中,每个文件都有自己的函数拷贝。没有用,因为内联做的事情几乎是一样的。
  • 通过减少工作来加快链接时间
  • 可以在每个翻译单元中放一个同名的函数,它们都可以做不同的事情。例如,您可以在每个 cpp 文件中放置一个 static void log(const char*) {},它们都可以以不同的方式记录。

关于c++ - static 关键字及其在 C++ 中的各种用途,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58938544/

相关文章:

python - 为什么在 C++ 中从 stdin 读取行比 Python 慢得多?

c++ - 如何使用gdbus-codegen生成的类型?

java - 静态类可以在java中有多个值吗(android java中的混淆示例)

c++ - 对类的静态成员的 undefined reference

Java 编译器无法识别静态内部类

java - NoClassDefFoundError 静态 vs 实例级别

java - 在 C++ 中使用 GetMethodID 两次

c++ - 结构绑定(bind)和变量类型

用于从动态应用程序创建静态二进制文件的 Linux 工具

c++ - double - 小数位