C++模板:全局对象中的静态成员未初始化

2024-01-31

我有一段简单的 C++ 代码,其中我通过专门化模板定义了一个模板和一个全局对象。对象构造函数访问专用模板中的静态成员。但事实证明静态成员此时尚未初始化。但对于本地对象(在函数体内定义),它是有效的。我很困惑...

我的c++编译器是:g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609

/////////////////////////
template<typename T>
class TB{
public:
  const char *_name;
  TB(const char * str):_name(str){
    cout << "constructor is called:" << _name << endl;
  };

  virtual ~TB(){
    cout << "destructor is called:" << _name << endl;
  };
};

template<typename T>
class TA{
public:
  const char *_name;
  TA(const char * str):_name(str){
    cout << "constructor is called:" << _name << endl;
    cout << tb._name <<endl;
  };

  virtual ~TA(){
    cout << "destructor is called:" << _name << endl;
  };

  static TB<T> tb;
};

template<typename T>
  TB<T> TA<T>::tb("static-tb");
TA<int> ta("global-ta");

int main(int argc,char ** argv){
  cout << "program started." << endl;
  cout << "program stopped." << endl;
  return 0;
}

/////////////////////////
//  OUTPUT:
constructor is called:global-ta
// yes, only such a single line.

如果我将 ta 的定义放入 main() 中,如下所示,它就可以工作。

int main(int argc,char ** argv){
  cout << "program started." << endl;
  TA<int> ta("local-ta");
  cout << "program stopped." << endl;
  return 0;
}

/////////////////////
//  OUTPUT:
constructor is called:static-tb
program started.
constructor is called:local-ta
static-tb
program stopped.
destructor is called:local-ta
destructor is called:static-tb
// end of output

在第一种情况下,您的程序在 main 启动之前崩溃了。它在构造函数内崩溃ta因为它访问tb尚未建成。这是一种形式静态初始化顺序惨败

第二种情况之所以成功是因为ta在里面main,这保证了tb这是非本地的,之前构建的ta.

问题是,为什么在第一种情况下,ta之前建造过tb虽然tb and ta在同一个编译单元中定义,tb之前定义的ta?

知道tb是模板静态数据成员,cppreference 中的这句话适用: http://en.cppreference.com/w/cpp/language/initialization

动态初始化

全部静态初始化完成后, 非局部变量的动态初始化发生在以下情况 情况:

1)无序动态初始化,仅适用于(静态/线程局部)变量模板和(C++11 起)类模板静态数据成员没有明确专门化的。此类静态变量的初始化相对于所有其他动态初始化的顺序是不确定的除非程序在初始化变量之前启动线程,在这种情况下其初始化是无序的 (C++17 起)。此类线程局部变量的初始化相对于所有其他动态初始化是无序的。

所以这里不保证顺序!自从ta是一个静态变量explicit模板特化,允许编译器在之前对其进行初始化tb.

同一页面的另一句话说:

早期动态初始化

如果满足以下条件,则允许编译器将动态初始化变量初始化为静态初始化的一部分(本质上是在编译时):

1) 动态版本的初始化不会在初始化之前更改名称空间范围内任何其他对象的值

2) 如果所有不需要静态初始化的变量都被动态初始化,静态版本的初始化在初始化变量中生成的值与动态初始化生成的值相同。由于上述规则,如果某个对象 o1 的初始化引用了命名空间范围的对象 o2,该对象可能需要动态初始化,但稍后在同一翻译单元中定义,则未指定所使用的 o2 的值是否为该值完全初始化的 o2 的值(因为编译器将 o2 的初始化提升到编译时),或者只是将 o2 的值初始化为零。

编译器决定根据这些规则来促进初始化ta before tb。是否被提升为静态初始化尚不清楚,但无论如何,很明显,当涉及到变量模板和静态模板成员时,初始化的顺序并不能得到保证,因为第一个引用和 的提升规则第二个报价。

Solution

为了保证tb在使用之前进行初始化,最简单的方法是将其放入包装函数中。我认为这应该是处理静态模板成员时的经验法则:

template<typename T>
class TA{
    //...
    static TB<T>& getTB();
};

template<typename T>
TB<T>& TA<T>::getTB()
{ static TB<T> tb("static-tb");
  return tb;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++模板:全局对象中的静态成员未初始化 的相关文章

随机推荐

  • Gridview 中的 TimeSpan DataFormatString

    我有一个带有来自 linq 查询的 ObjectDataSource 的 gridview 源的变量之一是时间跨度 我将绑定字段与 DataField MyTimeSpanVariable 绑定 数据包含以秒和分钟为单位的时间 很少以小时为
  • EF5 收到此错误消息:无法检查模型兼容性,因为数据库不包含模型元数据

    每次运行该应用程序时 都会显示此错误消息 我正在使用实体Framework 5 Code First 这是错误消息 System NotSupportedException Model compatibility cannot be che
  • 分布式 Elixir 示例不起作用

    我有一个非常简单的 Elixir 代码示例 我想在不同的节点上运行 第一个节点位于我的笔记本电脑上 第二个节点是 Raspberry Pi 通过 SSH 访问 代码很简单 node1 my computer defmodule Hello
  • Visual Studio 和 SQL Server - 安装顺序正确吗?

    我正在重建我的开发机器 这个问题对我来说并不新鲜 但我不记得解决方案 我从 SQL 2008 Developer 开始 然后是 VS 2008 Pro SQL SP1 VS SP1 结果是我无法打开SSIS项目 参见下面的错误 正确的顺序是
  • 监听 Flutter 中的 API 变化

    假设我有一个 API 它提供一个返回 id 和名称的 JSON 响应 在移动应用程序中 通常我会发出一个 http GET 响应 以便在与服务器的一次性连接中获取此数据 并在应用程序中显示结果 但是 如果数据随着时间的推移而变化 并且我想在
  • 如何在asp.net中显示Page_Load函数中设置的变量值

    我有一个从数据库获取的变量 我想在 html 之间的 aspx 页面中输出该变量 我试图将其公开 但它显示一些错误 如何在其 aspx 页面中使用页面加载函数中设置的变量 第一种方式 您将 Literal 控件放置在要显示变量的位置 然后在
  • 带有选项的简单选择标签在 Chrome 上不起作用

    我遇到了这个问题 我无法在我的 chrome 上扩展这个简单的选择标签
  • 在应用程序中使用多个网络接口

    我编写了一个应用程序 通过 wifi 触发索尼 qx 智能手机可连接相机 但是 我需要通过另一个本地网络实时传输手机上的图像 由于 wifi 卡用于 qx 连接 我需要能够通过 USB 使用以太网从手机传输图像 HTTP 请求将用于触发相机
  • 当手动将进度设置为 MotionLayout 时,它会清除所有约束

    我有带有两个小部件的 MotionLayout 一个在 MotionLayout 中描述 第二个在场景文件中描述 布局文件
  • 如何获取用户控件数据类型所在的TabPage

    我正在使用用户控件包装器方法构建自定义数据类型 我在其中添加现有的 TinyMCE 数据类型 问题是我需要找到一种方法来动态获取数据类型所在的当前 TabPage 以便我可以将 TinyMCE 按钮添加到菜单中 这就是我目前所拥有的 Tab
  • 使用 Ajax 和 PHP $_FILES 从 Canvas 元素发送图像

    我需要能够将图像和一些表单字段从客户端画布元素发送到 PHP 脚本 最终以 POST 和 FILES 结束 当我这样发送时
  • 将 Haskell 线程与内核线程进行比较 - 我的基准测试可行吗?

    这实际上是我的大学项目 在我的文章中 我需要提供证据证明 Haskell 线程的创建速度比普通内核线程更快 我知道最好参考一些研究论文 但重点是我必须自己进行基准测试 这是我的想法 我用 C 使用 pthreads 和 Haskell 编写
  • 错误“HttpServletRequest 引用了缺失的 String 类型”

    我正在 struts 中实现一个项目 其中 JSP 页面出现错误 我已经在 Eclipse IDE 中配置了 Tomcat 6 JRE 和 JDK 6 代码是 request getContextPath 错误是 The method ge
  • PHP 依赖注入

    我正在尝试了解依赖注入 并且在很大程度上我理解它 然而 如果由于某种原因 我的一个类依赖于多个类 而不是将所有这些都传递给构造函数中的这个类 是否有更好 更明智的方法 我听说过 DI 容器 这是我解决这个问题的方法吗 我应该从哪里开始使用这
  • 使用 PHPExcel 读取包含合并单元格的 Excel 工作表

    我想完整地阅读 Excel 工作表并使用 AJAX 将每一行发送到另一个页面进行处理 因此 我使用以下代码将 Excel 工作表数据转换为 JSON 数组 参考库中提供的 PHPExcel 示例
  • 如何使一个方法可用于 Rails 中的控制器和模型?

    我的 Rails 应用程序中有一个私有方法来连接到 Amazon S3 执行传递的代码块 然后关闭与 S3 的连接 看起来是这样 def S3 AWS S3 Base establish connection access key id g
  • Tomcat 中 System.setProperty 的范围

    这个问题是 表弟 这个涉及Android https stackoverflow com questions 4483001 scope of system setproperty 但我们在这里Tomcat环境 如果在我的网络应用程序中我设
  • Asp.net core 2 - 文件未发布

    EDIT 有关信息 我正在 macOS 上使用 VS Code 进行开发 我正在尝试将文件包含在我的发布过程中 当前cshtml这代表我的电子邮件模板 我遵循这个thread https github com dotnet sdk issu
  • 为什么 Spring Boot Batch 作业只运行一次?

    我正在使用弹簧靴 我有一个用这些类实现的批处理作业 我的主要课程是 SpringBootApplication ComponentScan com batch PropertySource classpath application pro
  • C++模板:全局对象中的静态成员未初始化

    我有一段简单的 C 代码 其中我通过专门化模板定义了一个模板和一个全局对象 对象构造函数访问专用模板中的静态成员 但事实证明静态成员此时尚未初始化 但对于本地对象 在函数体内定义 它是有效的 我很困惑 我的c 编译器是 g Ubuntu 5