是否需要在main之前初始化静态内联变量?

时间:2017-11-30 08:59:40

标签: c++ language-lawyer

如果我有A.h个文件(仅限标题):

#pragma once

struct A{
  static inline struct Initializer{
     Initializer(){
        std::cout << "init A" << std::endl;
     }
  } initializer;
};

#include "A.h"(来自另一个标头,它将包含在main.cpp中)是否足够,以便在Initializer::Initializer()之前调用main()

我读过标准要求在使用之前仅使用动态初始化来初始化静态变量。

  

是否是动态初始化的实现定义   完成命名空间作用域对象的(8.5,9.4,12.1,12.6.1)   在主要的第一个声明之前。如果初始化是延迟的   在主要的第一个陈述之后的某个时间点,它应该   在第一次使用之前定义的任何函数或对象之前发生   与要初始化的对象相同的翻译单元。

#include视为&#34;使用&#34;?

2 个答案:

答案 0 :(得分:3)

最新的工作草案在[basic.start.dynamic]/5中有更明确的措辞:

  

实现定义了具有静态存储持续时间的非本地内联变量的动态初始化是在main的第一个语句之前还是在延迟之前排序。如果延迟,强烈发生在该变量的非初始化odr使用之前。它是实现定义的,其中线程和程序中的哪些点发生延迟动态初始化。

其中:

  

非初始化odr-use是一种odr-use([basic.def.odr]),它不是由非本地静态或线程存储持续时间变量的初始化直接或间接引起的。

因此,回答你的问题:

  

#include&#34; A.h&#34;是否足够? (来自另一个标题,将由main.cpp包含),因此在main()之前调用Initializer::Initializer()

没有。 #include还不够。你必须odr-use它。

答案 1 :(得分:0)

当我在你的问题的评论中阅读tower120提供的网站时,我发现了这个:

  

具有静态存储持续时间的所有非局部变量在主函数执行开始之前被初始化为程序启动的一部分(除非延迟,见下文)。

http://en.cppreference.com/w/cpp/language/initialization

如果您的静态变量的初始化将被推迟,则同一网站会说

  

如果内联变量的初始化被推迟,则在第一次使用该特定变量之前发生。

&#34; ODR用途&#34;是访问变量或函数的地址(通过指针或引用)的情况。因此,如果您希望在A::Initializer::Initializer()之前调用main(),则必须将其地址(引用指针)分配给非延迟的静态变量,这将导致A::Initializer&# 39;第一次使用和A::Initializer::Initializer()的呼叫发生在main()

之前

#include也不被视为&#34;使用&#34;但是&#34;插入&#34;。 Include指令将文件的全部内容复制到它的位置。

这是一个简单的例子:

A.H

public class A {
    public:
        A() {};
    private:
        int var;
}

的main.cpp

#include "A.h"
int main()
{
    //Some Code
}

将成为此

public class A {
    public:
        A() {};
    private:
        int var;
}
int main()
{
    //Some Code
}

这就是为什么你需要包含警卫或#pragma once来阻止包含相同标题代码的两个文件来定义一个类或变量两次。