Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/399.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
什么';这是C++;与Java静态块等效的惯用语?_Java_C++_Initialization_Equivalent_Static Block - Fatal编程技术网

什么';这是C++;与Java静态块等效的惯用语?

什么';这是C++;与Java静态块等效的惯用语?,java,c++,initialization,equivalent,static-block,Java,C++,Initialization,Equivalent,Static Block,我有一个包含一些静态成员的类,我想运行一些代码来初始化它们(假设此代码无法转换为简单表达式)。在Java中,我只需要 class MyClass { static int myDatum; static { /* do some computation which sets myDatum */ } } 除非我错了,C++不允许使用这样的静态代码块,对吗?我该怎么做呢 我希望为以下两个选项提供解决方案: 在加载进程(或加载带有此类的DLL)时发生初始化

我有一个包含一些静态成员的类,我想运行一些代码来初始化它们(假设此代码无法转换为简单表达式)。在Java中,我只需要

class MyClass {
    static int myDatum;

    static {
        /* do some computation which sets myDatum */
    }
}

除非我错了,C++不允许使用这样的静态代码块,对吗?我该怎么做呢

我希望为以下两个选项提供解决方案:

  • 在加载进程(或加载带有此类的DLL)时发生初始化
  • 初始化发生在类第一次实例化时
  • 对于第二种选择,我想:

    class StaticInitialized {
        static bool staticsInitialized = false;
    
        virtual void initializeStatics();
    
        StaticInitialized() {
            if (!staticsInitialized) {
                initializeStatics();
                staticsInitialized = true;
            }
        }
    };
    
    class MyClass : private StaticInitialized {
        static int myDatum;
    
        void initializeStatics() {
            /* computation which sets myDatum */
        }
    };
    
    <>但是这是不可能的,因为C++(现在)不允许初始化非静态静态成员。但是,至少这将静态块的问题减少为通过表达式进行静态初始化的问题…

    您可以在C++中初始化静态数据成员:

    #include "Bar.h"
    
    Bar make_a_bar();
    
    struct Foo
    {
        static Bar bar;
    };
    
    Bar Foo::bar = make_a_bar();
    
    您可能需要考虑翻译单元之间的依赖关系,但这是一般的方法。

    对于#1,如果您确实需要在流程启动/库加载时进行初始化,则必须使用特定于平台的工具(例如Windows上的DllMain)

    但是,如果在执行与static相同的.cpp文件中的任何代码之前运行初始化就足够了,那么以下操作应该有效:

    // Header:
    class MyClass
    {
      static int myDatum;
    
      static int initDatum();
    };
    

    这样,保证在执行
    .cpp
    文件中的任何代码之前调用
    initDatum()

    如果不想污染类定义,还可以使用(C++11):

    别忘了最后一对括号——它实际上调用lambda


    至于#2,有一个问题:不能在构造函数中调用虚函数。最好在类中手动执行此操作,而不是使用基类:

    class MyClass
    {
      static int myDatum;
    
      MyClass() {
        static bool onlyOnce = []() -> bool {
          MyClass::myDatum = /*whatever*/;
          return true;
        }
      }
    };
    
    假设这个类只有一个构造函数,那么就可以了;它是线程安全的,因为C++ 11保证了初始化静态局部变量的安全性。

    C++中可以有静态块,也可以有外部类。 事实证明,我们可以实现一个Java风格的静态块,尽管是在类之外而不是在类内部,即在翻译单元范围内。在引擎盖下的实现有点难看,但使用时相当优雅

    可下载版本 现在,该解决方案有一个包含单个头文件的

    用法 如果你写:

    static_block {
        std::cout << "Hello static block world!\n";
    }
    
    以下是宏观工作,以将事物组合在一起:

    #define static_block STATIC_BLOCK_IMPL1(UNIQUE_IDENTIFIER(_static_block_))
    
    #define STATIC_BLOCK_IMPL1(prefix) \
        STATIC_BLOCK_IMPL2(CONCATENATE(prefix,_fn),CONCATENATE(prefix,_var))
    
    #define STATIC_BLOCK_IMPL2(function_name,var_name) \
    static void function_name(); \
    static int var_name __attribute((unused)) = (function_name(), 0) ; \
    static void function_name()
    
    注意事项:

    • 一些编译器不支持< C++ >代码> >代码>这不是C++标准的一部分;在这些情况下,上面的代码使用
      \uuuuuuuuuuuuuuuuuuuuuuuuuuuu
      ,这同样有效。GCC和Clang确实支持
      \uuuuu计数器\uuuuuu
    • 这是C++98;您不需要任何C++11/14/17构造。然而,尽管没有使用任何类或方法,它仍然不是有效的C
    • 如果您的C++11编译器不喜欢GCC风格的未使用扩展,则可以删除
      \u属性((未使用))
      ,或者将其替换为
      [[unused]]
    • 这并不能避免或有助于,因为虽然您知道静态块将在
      main()
      之前执行,但相对于其他静态初始化,您不能保证在什么时候执行

    你最好采取完全不同的方法。静态信息的集合实际上需要在StaticInitialized内部定义吗

    考虑创建一个单独的名为SharedData的单例类。然后,调用SharedData::Instance()的第一个客户端将触发共享数据集合的创建,这些数据将只是普通类数据,尽管它们位于静态分配的单个对象实例中:

    //SharedData.h

    class SharedData
    {
    public:
        int m_Status;
        bool m_Active;
    
        static SharedData& instance();
    private:
        SharedData();
    }
    
    //SharedData.cpp

    SharedData::SharedData()
    : m_Status( 0 ), m_Active( true )
    {}
    
    // static 
    SharedData& SharedData::instance()
    {
        static SharedData s_Instance;
        return s_Instance;
    }
    
    任何对共享数据集合感兴趣的客户机现在都必须通过SharedData单例访问它,第一个调用SharedData::instance()的此类客户机将在SharedData的ctor中触发该数据的设置,该数据只会被调用一次

    现在,您的代码表明不同的子类可能有自己的初始化静态数据的方法(通过initializeStatics()的多态性)。但这似乎是一个相当有问题的想法。多个派生类是否真的打算共享一组静态数据,但每个子类的初始化方式不同?这仅仅意味着,无论哪个类首先被构造,都将以自己的狭隘方式设置静态数据,然后其他所有类都必须使用此设置。这真的是你想要的吗


    我也有点困惑,为什么要尝试将多态性与私有继承相结合。您真正希望使用私有继承(而不是组合)的案例数量非常少。我想知道您是否认为需要initializeStatics()是虚拟的,以便派生类能够调用它。(事实并非如此)但您似乎确实希望重写派生类中的initializeStatics(),原因我不清楚(请参阅前面的内容)。整个设置似乎有些奇怪。

    下面是一个使用C++11模拟
    静态块的好方法:

    宏 定义CONCATE(X,Y)X#Y #定义CONCATE(X,Y)CONCATE_ux(X,Y) #定义唯一(名称)CONCATE(名称,行) 结构静态 { 模板静态_uT(仅_一次){仅_一次();} ~Static_(){}//以计数器“警告:未使用的变量” }; //如果我们希望函数中有多个'static'块,则需要'UNIQUE'宏 #定义静态uuUnique(块)=[&]()->void
    用法
    void foo()
    {
    STD::C++中的CUT没有这样的成语。
    原因在于从C++生成的代码的性质完全不同:运行时不是“托管”的。在编译后生成的代码中,不再存在“类”的概念,并且
    
    #define CONCATENATE(s1, s2) s1##s2
    #define EXPAND_THEN_CONCATENATE(s1, s2) CONCATENATE(s1, s2)
    #ifdef __COUNTER__
    #define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __COUNTER__)
    #else
    #define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __LINE__)
    #endif // __COUNTER__
    
    #define static_block STATIC_BLOCK_IMPL1(UNIQUE_IDENTIFIER(_static_block_))
    
    #define STATIC_BLOCK_IMPL1(prefix) \
        STATIC_BLOCK_IMPL2(CONCATENATE(prefix,_fn),CONCATENATE(prefix,_var))
    
    #define STATIC_BLOCK_IMPL2(function_name,var_name) \
    static void function_name(); \
    static int var_name __attribute((unused)) = (function_name(), 0) ; \
    static void function_name()
    
    class SharedData
    {
    public:
        int m_Status;
        bool m_Active;
    
        static SharedData& instance();
    private:
        SharedData();
    }
    
    SharedData::SharedData()
    : m_Status( 0 ), m_Active( true )
    {}
    
    // static 
    SharedData& SharedData::instance()
    {
        static SharedData s_Instance;
        return s_Instance;
    }
    
    #define CONCATE_(X,Y) X##Y
    #define CONCATE(X,Y) CONCATE_(X,Y)
    #define UNIQUE(NAME) CONCATE(NAME, __LINE__)
    
    struct Static_ 
    {
      template<typename T> Static_ (T only_once) { only_once(); }
      ~Static_ () {}  // to counter "warning: unused variable"
    };
    // `UNIQUE` macro required if we expect multiple `static` blocks in function
    #define STATIC static Static_ UNIQUE(block) = [&]() -> void
    
    void foo ()
    {
      std::cout << "foo()\n";
      STATIC
      {
        std::cout << "Executes only once\n";
      };  
    }
    
    #define M_CON(A, B) M_CON_(A, B)
    #define M_CON_(A, B) A##B
    
    #define STATIC_BLOCK \
            [[maybe_unused]] static const auto M_CON(_static_block,__LINE__) = []()
    
    #include <iostream>
    #include "static.hpp"
    
    STATIC_BLOCK {
       std::cout << "my static block" << '\n';
       int A,B,C,D = 12;
       std::cout << "my static block with " << A << '\n';    
       return 0; // this return is must
    }();
    
    int main(){
        std::cout << "in main function\n";
    }