问题
I'm currently learning C++, and I'm having some troubles.
I've developped a program by using lots of #define
, but I'd like to use static const
instead (collision/type/scopes...).
So, I now have something like:
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,
...
};
My code compiles with no warnings/errors (compiling with -W -Wall -Wextra -Werror flags).
However, when I try to run it, it results in a segfault.
I've ran it with valgrind, and it gave me the following ouput:
==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
So, the segfault occurs during the arrayOfString instanciation. I think the problem is that the arrayOfInt is allocated before the constant. But in that case, is it possible to use static const for this purpose?
I don't know how to patch this issue. Am I doing it wrong? Is there a better way to do it? How to solve this issue?
回答1:
Thanks to the comments, I finally solved the problem by using constexpr
keyword.
It gives me the following working code:
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,
...
};
回答2:
A generic workaround for static-init-fiasco problems is to wrap the static in a function, because variables inside functions do not have their initializers evaluated until the function is called.
That's not quite so straightforward when it's an array whose length is determined by the number of initializers. However, IMHO it is a poor design to access a global C-style array: either you have to pollute your code with range checks every time you use the array, or you risk doing an out-of-bounds access; and array bound errors are some of the hardest errors to debug at runtime.
Personally I'd replace the code with:
std::string &lookup_string(size_t n)
{
static std::string arrayOfString[] = { A::MY_CONST_VAR(), .... };
if ( n >= dimof(arrayOfString) ) throw....
return arrayOfString[n];
}
And also in the other file, if constexpr
is unavailable:
std::string MY_CONST_VAR() { return "some string"; }
Now there are no static fiascoes .
NB. I'm assuming you want write access to arrayOfString
, since you didn't declare it const
. If they are supposed to be read-only then further improvements can be made.
来源:https://stackoverflow.com/questions/24296706/c-static-initialization-order-fiasco