静态常量字符串不会被初始化

5
我有一些静态常量字符串作为我的C++类的私有成员。我知道在.h中声明,在.cpp中定义(和初始化)的做法。在类构造函数中,我调用一个使用这些静态字符串的函数。令人惊讶的是,在构造函数中,这些字符串保持未初始化状态(空字符串),这导致了问题。
有人能指出可能出了什么问题吗?我经常使用静态常量字符串,但从未遇到过这种情况。
更新:在utility()中,m_data保持为空。我有一个Test类对象作为另一个类的私有成员。
这是我正在使用的代码示例:
// Test.h
class Test
{
public:
  Test();
private:
  void utility();

 static const std::string m_data;
};

// Test.cpp
const std::string Test::m_data = "Data";

Test::Test()
{
utility();
}

void Test::utility()
{
//use m_data here
}

8
如果您不发布任何代码,您希望别人如何帮助您找出问题?ESP?(注:ESP可能指“Espressif Systems”,需根据上下文具体理解) - Ken White
3
我的猜测是这些是std::string对象(而不是const char*),并且类对象处于全局作用域,在某种原因下在静态字符串之前被构造;-) 这是我根据没有代码可以做到的。 - Michael Krelin - hacker
1
解释与 const char* 方式的区别:https://dev59.com/y3RB5IYBdhLWcg3w77on#459970 - Johannes Schaub - litb
2
当您添加代码时,您忘记了从哪里调用Test构造函数。 - Johannes Schaub - litb
1
为什么不在调试器中运行代码,在错误发生的地方停下来,然后在这里发布堆栈。这是我们唯一相信它不是静态初始化错误的方法。 - alex tingle
显示剩余5条评论
6个回答

5

您的TEST类型对象是全局的吗?

如果是,那么您遇到了初始化顺序的问题。

即:

int main()
{
    std::cout << "Main Entered" << std::endl;
    Test  t; // This should work
}
Test  plop; // This may not work depending

解决方案是使用静态方法获取字符串:
class Test
{
    static std::string const& getData()
    {
        static std::string const data("PLOP");
        return data;
    }
    // STUFF
    // Remove this line
    // static const std::string m_data;
    Test::Test()
    {
        std::cout << "Test::Test()" << std::endl;
        Utility();
    }
};
// If "Test::Test()" is printed before "Main Entered"
// You have a potential problem with your code.

测试对象不是全局的,而"data"是一个私有数据成员。 - AG
@AG 是一个用户定义的命名空间中的对象还是另一个类的静态成员? - Johannes Schaub - litb
@AG:getData() 是一个私有成员,因此不应影响您的代码。 - Martin York
如果测试对象是在由全局对象的构造函数调用的函数中创建的,则会产生相同的影响。基本上,如果在进入main函数之前调用Test::Test(),那么你将会遇到问题! - Martin York

4
你是这样定义它的吗?
class X
{
public:
      static string i;
};
string X::i = "blah"; // definition outside class declaration

参见:静态数据成员(仅限C++)


3

根据当前的代码,我猜想你试图创建全局的Test实例,很可能在另一个.cpp文件中。看起来你遇到了可怕的静态初始化顺序问题。简单来说,一个.cpp文件中的全局/静态成员变量会按照它们的定义顺序进行初始化。对于不同.cpp文件中的全局变量,没有任何保证,你不能指望一个文件中的变量在另一个文件中的全局变量之前或之后被初始化。


谢谢sbk,但我的Test实例不是全局的。它是另一个类的私有成员。 - AG
1
那个其他的类是否在全局范围内创建了一个实例?(重复直到到达类树的根部。) - Bill

1

这是你需要的吗?

class blah{
    static const string sz;
public:
    blah(){
        cout<<"blah constructor - string initialized to: "<<sz.c_str()<<endl;
    }
};

const string blah::sz("Hello, Blah!");

int _tmain(int argc, _TCHAR* argv[]){
    blah b;
    return 0;
}

程序输出: blah 构造函数 - 字符串初始化为: Hello, Blah!


0

我会采用不同的方法:

class Test
{
public:
    Test() : m_data( "Data" ) {}
private:
     const std::string m_data;
};

我个人更喜欢这种“风格”,这样可以避免在构造函数中初始化数据所引起的问题,而每个实例构造字符串的代价很小。

谢谢Patrick,但我想让数据是静态的,这种情况下它不能使用初始化列表进行初始化。 - AG
除非您在初始化数据时遇到问题(这是在尝试后才能确定的),否则拥有静态const变量没有任何意义。const数据不可更改,因此它是否为静态都无关紧要,它始终保持不变。 - Patrick

0

我对程序进行了检查,它运行正常。你用的是哪个IDE?这是在Windows上,对吧?

如果我理解错误,你可以在声明成员变量的类本身中进行定义,因为它是一个const static。


我进行了检查,根据Visual Studio IDE的规定,您只能输入整数值进入该类。 - Boris Raznikov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接