草庐IT

C++静态成员初始化(模板好玩里面)

coder 2023-05-02 原文

对于静态成员初始化,我使用嵌套的帮助器结构,它适用于非模板化类。
但是,如果封闭类由模板参数化,则如果在主代码中未访问辅助对象,则不会实例化嵌套的初始化类。
为了说明,一个简化的例子(在我的例子中,我需要初始化一个 vector )。

#include <string>
#include <iostream>

struct A
{
    struct InitHelper
    {
        InitHelper()
        {
            A::mA = "Hello, I'm A.";
        }
    };
    static std::string mA;
    static InitHelper mInit;

    static const std::string& getA(){ return mA; }
};
std::string A::mA;
A::InitHelper A::mInit;


template<class T>
struct B
{
    struct InitHelper
    {
        InitHelper()
        {
            B<T>::mB = "Hello, I'm B."; // [3]
        }
    };
    static std::string mB;
    static InitHelper mInit;

    static const std::string& getB() { return mB; }
    static InitHelper& getHelper(){ return mInit; }
};
template<class T>
std::string B<T>::mB; //[4]
template<class T>
typename B<T>::InitHelper B<T>::mInit;


int main(int argc, char* argv[])
{
    std::cout << "A = " << A::getA() << std::endl;

//    std::cout << "B = " << B<int>::getB() << std::endl; // [1]
//    B<int>::getHelper();    // [2]
}

使用 g++ 4.4.1:
  • [1] 和 [2] 评论道:

    A = 你好,我是 A。

    按预期工作
  • [1] 未注释:

    A = 你好,我是 A。
    乙 =

    我希望 InitHelper 初始化 mB
  • [1] 和 [2] 未注释:

    A = 你好,我是 A。
    B = 你好,我是 B。

    按预期工作
  • [1] 评论,[2] 未评论:
    [3]
  • 静态初始化阶段的段错误

    因此我的问题是:这是一个编译器错误还是位于显示器和椅子之间的错误?
    如果是后者:是否有一个优雅的解决方案(即没有显式调用静态初始化方法)?

    更新一:
    这似乎是一种理想的行为(如 ISO/IEC C++ 2003 标准 14.7.1 中所定义):

    Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.

    最佳答案

    前段时间在 usenet 上讨论过这个问题,当时我正在尝试回答有关 stackoverflow 的另一个问题:Point of Instantiation of Static Data Members .我认为减少测试用例并单独考虑每个场景是值得的,所以让我们先更一般地看一下它:

    struct C { C(int n) { printf("%d\n", n); } };
    
    template<int N>
    struct A {
      static C c;
    }; 
    
    template<int N>
    C A<N>::c(N); 
    
    A<1> a; // implicit instantiation of A<1> and 2
    A<2> b;
    

    您已经定义了静态数据成员模板。这还没有创建任何数据成员,因为 14.7.1 :

    "... in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist."



    根据定义该词的一个定义规则(在 3.2/2 处),当“使用”该实体时,需要对该实体(= 实体)进行定义。特别是,如果所有引用都来自未实例化的模板、模板的成员或 sizeof不“使用”实体的表达式或类似的东西(因为它们要么没有潜在地评估它,要么它们只是作为本身使用的函数/成员函数不存在),这样的静态数据成员不会被实例化.
    14.7.1/7 的隐式实例化实例化静态数据成员的声明——也就是说,它将实例化处理该声明所需的任何模板。但是,它不会实例化定义——也就是说,不会实例化初始值设定项,并且不会隐式定义该静态数据成员类型的构造函数(标记为已使用)。

    这意味着,上面的代码不会输出任何内容。现在让我们对静态数据成员进行隐式实例化。
    int main() { 
      A<1>::c; // reference them
      A<2>::c; 
    }
    

    这会导致两个静态数据成员存在,但问题是——初始化的顺序是怎样的?简单地读一读,人们可能会认为 3.6.2/1适用,其中说(我强调):

    "Objects with static storage duration defined in namespace scope in the same translation unit and dynamically initialized shall be initialized in the order in which their definition appears in the translation unit."



    现在正如在 usenet 帖子中所说和解释的 in this defect report ,这些静态数据成员未在翻译单元中定义,但在实例化单元中实例化,如 2.1/1 所述。 :

    Each translated translation unit is examined to produce a list of required instantiations. [Note: this may include instantiations which have been explicitly requested (14.7.2). ] The definitions of the required templates are located. It is implementation-defined whether the source of the translation units containing these definitions is required to be available. [Note: an implementation could encode sufficient information into the translated translation unit so as to ensure the source is not required here. ] All the required instantiations are performed to produce instantiation units. [Note: these are similar to translated translation units, but contain no references to uninstantiated templates and no template definitions. ] The program is ill-formed if any instantiation fails.



    这样一个成员的实例化点也并不重要,因为这样的实例化点是实例化与其翻译单元之间的上下文链接——它定义了可见的声明(如 14.6.4.1 所指定,以及每个这些实例化点必须赋予实例化相同的含义,如 3.2/5 处的一个定义规则中指定的,最后一个项目)。

    如果我们想要有序的初始化,我们必须安排这样我们不会混淆实例化,而是使用显式声明 - 这是显式特化的领域,因为它们与普通声明并没有真正不同。事实上,C++0x 改变了它的措辞 3.6.2到以下几点:

    Dynamic initialization of a non-local object with static storage duration is either ordered or unordered. Definitions of explicitly specialized class template static data members have ordered initialization. Other class template static data members (i.e., implicitly or explicitly instantiated specializations) have unordered initialization.



    这对您的代码意味着:
  • [1] [2] 评论:不存在对静态数据成员的引用,因此它们的定义(也不是它们的声明,因为不需要实例化 B<int> )没有实例化。不会发生副作用。
  • [1] 未注释:B<int>::getB()使用,它本身使用 B<int>::mB ,这要求该静态成员存在。字符串在 main 之前初始化(在任何情况下,在该语句之前,作为初始化非本地对象的一部分)。没什么用 B<int>::mInit ,所以它没有被实例化,所以没有 B<int>::InitHelper 的对象永远被创建,这使得它的构造函数不被使用,反过来它永远不会给 B<int>::mB 赋值。 : 你只会输出一个空字符串。
  • [1] [2] 未评论:这对你有用是运气(或相反:))。如上所述,不需要特定的初始化调用顺序。它可能在 VC++ 上工作,在 GCC 上失败并在 clang 上工作。我们不知道。
  • [1] 评论, [2] 未注释:同样的问题 - 再次使用两个静态数据成员:B<int>::mInitB<int>::getHelper 使用,以及 B<int>::mInit 的实例化将导致其构造函数被实例化,这将使用 B<int>::mB - 但是对于您的编译器,此特定运行中的顺序是不同的(未指定的行为不需要在不同的运行中保持一致):它初始化 B<int>::mInit首先,它将对尚未构造的字符串对象进行操作。
  • 关于C++静态成员初始化(模板好玩里面),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1819131/

    有关C++静态成员初始化(模板好玩里面)的更多相关文章

    1. 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”因此,为了解决

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

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

    3. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

      我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

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

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

    5. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

      对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

    6. ruby-on-rails - ActionController::RoutingError: 未初始化常量 Api::V1::ApiController - 2

      我有用于控制用户任务的Rails5API项目,我有以下错误,但并非总是针对相同的Controller和路由。ActionController::RoutingError:uninitializedconstantApi::V1::ApiController我向您描述了一些我的项目,以更详细地解释错误。应用结构路线scopemodule:'api'donamespace:v1do#=>Loginroutesscopemodule:'login'domatch'login',to:'sessions#login',as:'login',via::postend#=>Teamroutessc

    7. ruby - 这两个 Ruby 类初始化定义有什么区别? - 2

      我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是

    8. ruby - 使用 `+=` 和 `send` 方法 - 2

      如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

    9. ruby-on-rails - Mandrill API 模板 - 2

      我正在使用Mandrill的RubyAPIGem并使用以下简单的测试模板:testastic按照Heroku指南中的示例,我有以下Ruby代码:require'mandrill'm=Mandrill::API.newrendered=m.templates.render'test-template',[{:header=>'someheadertext',:main_section=>'Themaincontentblock',:footer=>'asdf'}]mail(:to=>"JaysonLane",:subject=>"TestEmail")do|format|format.h

    10. ruby - Chef Ruby 遍历 .erb 模板文件中的属性 - 2

      所以这可能有点令人困惑,但请耐心等待。简而言之,我想遍历具有特定键值的所有属性,然后如果值不为空,则将它们插入到模板中。这是我的代码:属性:#===DefaultfileConfigurations#default['elasticsearch']['default']['ES_USER']=''default['elasticsearch']['default']['ES_GROUP']=''default['elasticsearch']['default']['ES_HEAP_SIZE']=''default['elasticsearch']['default']['MAX_OP

    随机推荐