Java风格的静态常量初始化

java style static constant initialization

本文关键字:常量 初始化 静态 风格 Java      更新时间:2023-10-16

我是一个c++新手。我试图在c++中创建一个静态常量容器。在java中,我们通常通过静态常量初始化来实现。例如

class ConstantDefinition {
  public static const List<String> stringList = new ArrayList<String>();
  static {
       stringList.add("foo");
       stringList.add("boo");
       ...blah
       }                       
} 

java的工作方式,我不需要调用一个特定的方法来完成初始化。静态块在类加载到JVM中时被初始化。但是在c++中,我们没有与java相同的类加载机制。我想要的是有一个不可修改容器的副本,我可以使用,而不必每次都创建类对象。我理解的一种方法是创建一个类(类似于上面的java示例)并定义一个const静态容器。但我发现在c++中编写这种代码很困难,因为我不能在不调用方法的情况下进行初始化。那么,实现这一目标的最佳方式是什么呢?第二种方法是定义头文件并在名称空间内初始化全局变量。如果我采取这种方法,那么它会创建不同的全局变量,每次当我包括头文件或相同的一个将被使用?

谢谢,RG

有几种解决方案,取决于操作的复杂程度实际初始化是多少,以及是否可以指望c++ 11或不是。在所有情况下,解决方案都取决于这样一个事实构造函数在静态变量上调用已加载执行

在最简单的情况下,您只需用an来定义变量初始化参数,例如:

在课堂上:

class ConstantDefinition
{
    static std::vector<std::string> const stringList;
    //  ...
};

(对于所有的解都是一样的)

在源文件中:

std::vector<std::string> const ConstantDefinition::stringList{
    "foo",
    "boo",
    //  ...
}

这只适用于c++ 11。使用早期版本的在c++中,您需要定义变量:

std::string const stringListInit[] =
{
    "foo",
    "boo",
    //  ...
};
std::vector<std::string> const ConstantDefinition::stringList(
    begin( stringListInit ), end( stringListInit ) );

您还需要函数beginend:

template <typename T, size_t N>
T* begin( T (&array)[N} ) { return array; }
template <typename T, size_t N>
T* end( T (&array)[N] ) { return array + N; }

如果你没有c++ 11(它们在标准中)库),无论如何你都会需要它们。

不要忘记,在任何一个初始化列表中,你都可以使用任意表达式进行初始化,包括函数调用.

最后,如果您的初始化过于复杂,您可以始终将其封装在函数中:

namespace {
std::vector<std::string> stringListInit()
{
    std::vector<std::string> results;
    results.push_back( "foo" );
    //  ...
    return results;
}
}
std::vector<std::string> const ConstantDefinition::stringList( stringListInit() );

不要太担心创建数组,它将是复制,然后销毁;c++允许NRVO,这意味着编译器实际上可以"合并"本地变量在stringListInitConstantDefinition::stringList,所以只有一个std::vector<std::string>实际构建

如果将此代码放入任何编译单元(可能是源文件)

namespace {
    static struct Initialiser
    {
        Initialiser()
        {
            // ToDo - initialisation code here
        }
    } TheInitialiser;
}

然后代码块将在加载库/可执行文件后运行(并且在调用main函数之前)。这个成语很常见。

外部namespace{}(称为匿名命名空间)块防止将此代码发送到链接器和其他编译单元中。

In ConstantDefinition.hpp:

#include <string>
#include <vector>
struct ConstantDefinition
{
    static const std::vector<std::string> string_array;
};

In ConstantDefinition.cpp:

const std::vector<std::string> ConstantDefinition::string_array =
{
    "foo",
    "boo"
};

注意: c++ 11或更高要求。