3

我目前正在学习C++,并且遇到一些麻烦。C++静态初始化命令失败

我开发了一个程序,使用大量的#define,但我想用static const代替(碰撞/类型/范围...)。

所以,我现在有这样的:

file1.hpp

class A { 
    public: 
    static const std::string MY_CONST_VAR; 
}; 

file1.cpp

const std::string A::MY_CONST_VAR = "some string"; 

file2.cpp

static std::string arrayOfString[] = { 
    A::MY_CONST_VAR, 
    ... 
    }; 

我的代码编译时没有警告/错误(使用-W -Wall -Wextra -Werror标志编译)。

但是,当我尝试运行它时,它会导致段错误。

我和Valgrind的运行它,它给了我下面的输出中:

==11239== Invalid read of size 4 
==11239== at 0x5F525CB: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19) 
==11239== by 0x40D076: _GLOBAL__sub_I__ZN16GraphicInterface13DEFAULT_WIDTHE (GraphicInterface.cpp:42) 
==11239== by 0x51AC7C: __libc_csu_init (in /home/simon/PSU_2013_zappy/gui/gui_zappy) 
==11239== by 0x66D8E54: (below main) (libc-start.c:246) 
==11239== Address 0xfffffffffffffff8 is not stack'd, malloc'd or (recently) free'd 

所以,arrayOfString instanciation期间发生段错误。我认为问题是arrayOfInt是在常量之前分配的。但在这种情况下,是否可以使用静态常量来达到这个目的?

我不知道如何修补这个问题。 我做错了吗?有没有更好的方法来做到这一点?如何解决这个问题?

+0

“segfault在arrayOfInt instanciation期间发生”?是什么让你得出这样的结论? valgrind报告指出'std :: basic_string'构造函数中发生了什么。我在你发布的代码中看不到'std :: basic_string'的任何用法,它肯定不是'arrayOfInt'。 – AnT

+5

检查[静态初始化顺序失败](http://www.parashift.com/c++-faq/static-init-order.html)上的常见问题。 –

+0

@AndreyT我在我的例子中使用了int,但是我在程序中使用了字符串。这就是我为什么总结这一点。我会编辑我的问题以使其更清楚。 –

回答

2

感谢评论,我终于通过使用constexpr关键字解决了这个问题。

它给了我下面的工作代码:

file1.hpp

class A { 
    public: 
    static constexpr char MY_CONST_VAR[] = "some string"; 
}; 

file1.cpp

const char A::MY_CONST_VAR[]; 

file2.cpp

static std::string arrayOfString[] = { 
    A::MY_CONST_VAR, 
    ... 
}; 
+1

但'constexpr'仅在C++ 11中引入。祝您携带方便。 – Kaz

+0

它在兼容性无关紧要的C/C++学校项目上下文中。否则,我会在静态变量周围做一些包装,就像前面在评论中提到的那样。 –

+1

no no,继续使用它,这样每个人都可以提高编译器的性能=) –

3

对于static-init-fiasco问题的通用解决方法是将静态包装到函数中,因为函数内部的变量在调用该函数前没有对其初始化器进行评估。

当它是一个长度由初始值设定项决定的数组时,这并不那么简单。但是,恕我直言,访问全局C风格的数组是一种糟糕的设计:每次使用数组时,您都必须使用范围检查来污染代码,否则您可能会冒险进行超出边界的访问;和数组绑定错误是在运行时进行调试的一些最难的错误。

个人而言,我会替换代码:

std::string &lookup_string(size_t n) 
{ 
    static std::string arrayOfString[] = { A::MY_CONST_VAR(), .... }; 

    if (n >= dimof(arrayOfString)) throw.... 
    return arrayOfString[n]; 
} 

以及在其他文件中,如果constexpr不可用:

std::string MY_CONST_VAR() { return "some string"; } 

现在有没有静态的失败案例。

注意:我假设你想要写入arrayOfString,因为你没有声明const。如果它们应该是只读的,那么可以进一步改进。

+0

对于'generic workaround'部分是这样的(+)......但是,老实说,我发现常量(特别是当UPPER_CASED)看起来相当糟糕后面的圆括号 - 你真的*喜欢它吗? – Wolf