【问题标题】:Fix static const std::string member[] initialization修复静态 const std::string member[] 初始化
【发布时间】:2013-08-30 12:22:37
【问题描述】:

这个主题可能已经被处理了,但我找不到这个问题的解决方案。 我在这样的类中声明了一个static const std::string[] 成员:

.h:

class MyClass
{
private:
    static const std::string cArray[aNumber];

    //other stuff like ctors & all
}

.cpp

const std::string MyClass::cArray[] = {"", "ini", "txt", "bmp"};

这个类包含在另一个标题中,我声明了 MyClass 的 static const array[]。 问题是:在构建这些数组时,m_cArray 包含我用来修复其他静态数组中的内容的空字符串。

我看到了一些关于静态初始化顺序问题的帖子,但我没有找到有用的答案。

欢迎提出建议。谢谢

【问题讨论】:

  • -1:现在一团糟。由于问题已经完全改变,答案已经经过多次修改。
  • 我不这么认为。我同意我犯了一些错误,但主题很清楚。此外,syam 解决了我的问题。

标签: c++ arrays static initialization constants


【解决方案1】:

您在定义静态成员时忘记指定 cArray 属于 MyClass 类:

const std::string MyClass::cArray[] = {"", "ini", "txt", "bmp"};
//                ^^^^^^^^^^^^^^^

编辑:

您的问题似乎是 C++ 中未定义静态成员的初始化顺序。

正如here 所说,最优雅的解决方法是将初始化包装在一个函数中:

class MyClass
{
private:
    static std::string* Array()
    {
        static std::string cArray[aNumber] = {"", "ini", "txt", "bmp"};
        return cArray;
    }
};

然后你访问你的数组:

MyClass::Array();

编辑:您在示例中纠正了这个错误

也许您的另一个错误可能是您在类声明中将您的成员命名为 cArray

class MyClass
{
private:
    static const std::string cArray[aNumber];
    //                       ^^^^^^
};

m_cArray在成员定义中:

const std::string m_cArray[] = {"", "ini", "txt", "bmp"};
//                ^^^^^^^^

我在我的第一个代码示例中更正了这个错误。

【讨论】:

  • 另外,它叫cArray,而不是m_cArray
  • @LightnessRacesinOrbit 感谢您指出这一点。我没有看到这个错误,因为我习惯这样命名成员。
  • 无论如何,除了我长期酗酒导致的错误之外,问题仍然存在:)。当我在以下标头中使用一些使用 cArray 的方法时,我得到空字符串来代替初始内容:/
  • @Weldryn 看看this example。它似乎工作正常......而且它在家里也可以使用不同标题中的类声明。
  • @PierreFourgeaud OP 的问题似乎来自静态初始化命令的惨败,所以我非常怀疑您能否用单个翻译单元重现他的问题。 ;)
【解决方案2】:

你需要在初始化的时候说明cArray是哪个类的成员

const std::string MyClass::cArray[] = {"", "ini", "txt", "bmp"};

【讨论】:

  • 谢谢,我刚刚更新了我的答案,涵盖了那个错字。答案现在再次更新:)
【解决方案3】:

您的问题似乎确实源于臭名昭著的静态初始化命令惨败

基本上,当您在一个翻译单元中有一个static 变量X,在第二个翻译单元中引用另一个static 变量Y,那么您的程序有50/50 的错误行为机会。为了正常运行,Y 应该在 X 之前初始化,但 C++ 不强制这样做。

据我所知,处理此问题的唯一正确方法是使用函数级 static 变量,这确保 m_array 将在首次调用 MyClass::array() 时被初始化(以及在 C++11这个初始化甚至保证是线程安全的):

struct MyClass {
    static const size_t arraySize = 4;

    // This function could be defined in a .cpp rather than inline
    // I only put it inside the class for compactness/readability reasons
    static const std::string* array() {
        static const std::string m_array[arraySize] = {"", "ini", "txt", "bmp"};
        return m_array;
    }
};

// In some other file
struct OtherClass {
    // This function could be defined in a .cpp rather than inline
    static void whatever() {
        do_something_with(MyClass::array());
    }
};

换句话说,您应该避免声明 static 全局变量或类变量(除非您绝对确定它们可以解析为编译时常量,例如上面的 arraySize),但是换行它们在 static 函数内部的函数级别。


附带说明一下,这个习惯用法使您可以更轻松地使用适当的容器而不是传统的 C 数组,例如。 std::vector 或者,如果你使用 C++11,std::array:

// C++03
struct MyClass {
    // This function could be defined in a .cpp rather than inline
    static const std::vector<std::string>& data() {
        static std::vector<std::string> m_data;
        if (m_data.empty()) {
            m_data.push_back("");
            m_data.push_back("ini");
            m_data.push_back("txt");
            m_data.push_back("bmp");
        }
        return m_data;
    }
};

// C++11
struct MyClass {
    using Container = std::vector<std::string>;
    // or
    // using Container = std::array<std::string, 4>;

    // This function could be defined in a .cpp rather than inline
    static const Container& data() {
        static const Container m_data = {"", "ini", "txt", "bmp"};
        return m_data;
    }
};

【讨论】:

  • 我明白你的意思,但不明白你写的代码(第一部分,无论如何)。我的编译器是 VS2008,所以我不能使用 array 类型。第二部分对我来说很容易理解:如果我没记错的话,你使用工厂函数?
  • @Weldryn 我使用的是 C++11 功能,但是当我看到您使用 C++03 时我对其进行了编辑,所以您现在应该可以使用了。至于第二部分,那不是工厂函数(工厂的意思,每次都创建新对象),而是函数级静态变量启用的“construct on first use”习语。只有一个 m_data 实例,就像在您的原始代码中一样,但它在第一次调用该函数时被初始化,因此您成为受害者的惨败不会发生。
猜你喜欢
  • 2016-02-04
  • 2019-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-18
  • 2020-10-07
  • 2012-12-15
  • 2016-10-05
相关资源
最近更新 更多