【问题标题】:c++ - java style static constant initializationc++ - java风格的静态常量初始化
【发布时间】:2014-05-23 13:33:57
【问题描述】:

我是 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

【问题讨论】:

  • 你不需要的部分是new
  • Cody,我写的是java代码,我们确实需要java中的新代码。
  • 相关:[C++ 的成语相当于 Java 的静态块是什么? ](stackoverflow.com/q/19227664/514235)

标签: c++ static initialization constants


【解决方案1】:

有几种解决方案,具体取决于复杂程度 实际初始化是,你是否可以指望 C++11 或 不是。在所有情况下,解决方案取决于以下事实: 当代码运行时,对静态变量调用构造函数 加载执行。

在最简单的情况下,您只需使用 初始值,例如:

在课堂上:

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, 这意味着编译器实际上可以“合并”本地 stringListInit 中的变量和 ConstantDefinition::stringList,所以只有一个 std::vector&lt;std::string&gt; 实际构造。

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

    • 如果我在 struct Initializer 中定义一个向量并在构造函数中对其进行初始化,它似乎可以工作。但是我不能使向量保持不变。那么如何绕过这个限制呢?在这种情况下,我是否需要在打算使用此结构的同一文件中定义此匿名命名空间,还是可以在单独的源文件中定义它?如果我在单独的源文件中定义它,那么我应该执行 #include (不确定,但在 #include 中添加 .cpp 对我来说并不合适)。另外,出于我理解的目的,我认为我们可以创建多个结构对象,对吧?
    【解决方案3】:

    在 ConstantDefinition.hpp 中:

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

    在 ConstantDefinition.cpp 中:

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

    注意:需要 C++11 或更高版本。

    【讨论】:

      猜你喜欢
      • 2012-08-18
      • 2011-02-06
      • 2010-12-11
      • 2011-10-06
      • 1970-01-01
      • 2016-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多