草庐IT

c++ - 静态对象是否保证被初始化

coder 2023-06-03 原文

我正在尝试了解静态对象的初始化。假设您了解常量表达式和 constexpr,静态初始化看起来很简单。动态初始化似乎有点棘手。

[basic.start.init]/4

It is implementation-defined whether the dynamic initialization of a non-local variable with static storage duration is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first odr-use (3.2) of any function or variable defined in the same translation unit as the variable to be initialized.

脚注 34

A non-local variable with static storage duration having initialization with side-effects must be initialized even if it is not odr-used (3.2, 3.7.1).

[basic.start.init]/5

It is implementation-defined whether the dynamic initialization of a non-local variable with static or thread storage duration is done before the first statement of the initial function of the thread. If the initialization is deferred to some point in time after the first statement of the initial function of the thread, it shall occur before the first odr-use (3.2) of any variable with thread storage duration defined in the same translation unit as the variable to be initialized.

我假设“线程的初始函数”指的是 main,而不仅仅是以 std::thread 开头的线程。

h1.h

#ifndef H1_H_
#define H1_H_

extern int count;

#endif

tu1.cpp

#include "h1.h"

struct S
{
   S()
   {
      ++count;
   }
};

S s;

tu2.cpp

#include "h1.h"

int main(int argc, char *argv[])
{
   return count;
}

tu3.cpp

#include "h1.h"

int count;

因此,如果编译器推迟动态初始化,脚注 34 似乎指出 s 必须在某个时候进行初始化。由于翻译单元中没有其他具有动态初始化的变量,因此没有其他变量可以使用 odr 来强制初始化 tu1 中的变量。 s 在什么时候保证被初始化?

main 是否保证返回 1?另外,有没有办法改变这个程序,使它不再保证返回 1?或者,如果不能保证,有没有办法改变这个程序,使它成为保证?


我分解了代码,以便 s 的定义位于与 main 不同的翻译单元中。这避免了 main 是否使用 odr 的问题。鉴于 s 是翻译单元中唯一的对象,是否保证 main 将返回 1?

最佳答案

我认为所有这些措辞都是为了描述动态加载的库中会发生什么,但没有明确命名它们。

总结一下我的解释:具有静态存储持续时间和动态初始化的非局部变量将:

  1. 在第一次使用翻译单元中的任何内容之前进行初始化;
  2. 可能在开始 main 之前,但也可能在它之后。

我将脚注 34 解释为(但请记住,脚注不是规范性的):

When anything in a TU is ord-used, then every non-local variable with static storage duration having initialization with side-effects must be initialized, even the variables that are not odr-used.

所以,如果有一个 TU 没有使用任何东西,那么它的动态初始化可能不会发生。

示例

h1.h

extern int count;
struct S
{
    S();
};

h1.cpp

#include "h1.h"

int count;
S::S()
{
   ++count;
}

h2.cpp

#include "h1.h"
S s;

main.cpp

#include "h1.h"
#include <stdio.h>
int main()
{
    printf("%d\n", count);
}

这可以打印 0 或 1:由于 TU h2 中的任何内容都不会被 odr 使用,因此未指定 s 的代码初始化何时完成(如果有的话)。

自然,理智的编译器会在 main 之前初始化 s,所以它肯定会打印 1:

$ g++ main.cpp h2.cpp h1.cpp -o test1
$ ./test1
1

现在,假设 h2.cpp 在共享库中:

$ g++ -shared -fPIC h2.cpp -o h2.so

现在主要文件是:

main2.cpp

#include "h1.h"
#include <dlfcn.h>
#include <stdio.h>

int main()
{
    printf("%d\n", count);
    dlopen("./h2.so", RTLD_NOW);
    printf("%d\n", count);
    return 0;
}

编译运行:

$ g++ -shared -fPIC h2.cpp -o h2.so
$ g++ -rdynamic main.cpp h1.cpp -ldl -o test2
$ ./test2
0
1

看到了吗? s 的初始化被延迟了!好的部分是,如果不先加载动态加载库,就无法引用动态加载库中的任何内容,加载它会触发动态初始化。所以一切都很好。

如果您认为使用 dlopen 是作弊,请记住有些编译器支持延迟加载共享库(例如 VC++),其中加载库的系统调用将由编译器只是第一次需要它。

关于c++ - 静态对象是否保证被初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18600034/

有关c++ - 静态对象是否保证被初始化的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  3. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  4. ruby-on-rails - 未初始化的常量 Psych::Syck (NameError) - 2

    在我的gem中,我需要yaml并且在我的本地计算机上运行良好。但是在将我的gem推送到ruby​​gems.org之后,当我尝试使用我的gem时,我收到一条错误消息=>"uninitializedconstantPsych::Syck(NameError)"谁能帮我解决这个问题?附言RubyVersion=>ruby1.9.2,GemVersion=>1.6.2,Bundlerversion=>1.0.15 最佳答案 经过几个小时的研究,我发现=>“YAML使用未维护的Syck库,而Psych使用现代的LibYAML”因此,为了解决

  5. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  6. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  7. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  8. ruby - 检查数组是否在增加 - 2

    这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife

  9. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  10. ruby-on-rails - 未在 Ruby 中初始化的对象 - 2

    我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调

随机推荐