c++ static initialization order fiasco

只谈情不闲聊 提交于 2021-01-27 11:21:20

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!