Pregunta

Recently I've come across strange C++ behavior I cannot understand. I have a header file like this:

1:  struct LogLevel {
2:  public:
3:    static const LogLevel ERROR;
4:
5:    LogLevel(int id) : _id(id) {}
6:
7:  private:
8:     int _id;
9:     std::string _name;
10: };

And then separate C++ implementation file:

1:  LogLevel l = LogLevel::ERROR;
2:  const LogLevel LogLevel::ERROR(1);

Line 1 causes segmentation fault. I know it has something to do with uninitialized memory, but I can't understand what is going on behind the bars.

If you swap lines 1 and 2 in implementation file, then everything is OK.

What is very confusing for me is, that everything is also OK if you just comment-out line 9 from header file with definition of std::string member.

Does anyone have sensible explanation ?

¿Fue útil?

Solución

Within the same unit, static variables get initialized in the order of their definitions.

So when you have the line:

LogLevel l = LogLevel::ERROR;

the variable LogLevel::ERROR has not yet had its constructor run. This causes undefined behaviour. The reason this UB manifests itself as a segfault could be because you copy a std::string by value which has not been initialized, so its internal pointer will be wild.

Reversing the order of the definitions fixes the problem, as then LogLevel::ERROR does exist when you try and assign it to l.

NB. It'd be preferable to make l static. This prevents you accidentally referring to it from another unit, so you avoid the static initialization order problem. If you intentionally want to refer to it from another unit, you'll have to make sure that you do not access it in that unit before main() has been entered.

Otros consejos

You can't use a value until it's initialized.

LogLevel l = LogLevel::ERROR;

The default copy constructor attempts to copy ERROR._name to l._name, even though ERROR._name hasn't been initialized yet. This is undefined behavior and can cause a crash. As you noticed, the solution is to change the order of the two lines of code.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top