Глобальные константы не определены в конструкторе - PullRequest
0 голосов
/ 14 ноября 2018

У меня есть два файла для констант:

// constants.h
extern const std::string testString;

// constants.cpp
const std::string testString = "defined!";

Мне нужно использовать эту константу в конструкторе объекта при инициализации программы, но она получается неопределенной.Код в конструкторе:

MyClass::MyClass() {
   printf("Value of test string: %s", testString.c_str());
}

// output:
Value of test string: (null)

Класс и константы определены в одном и том же пространстве имен, и это не дает мне ошибку, что константа не определена.После того как объект инициализирован (например, с помощью жестко запрограммированной строки), он работает нормально и выводит значение константы («определено!»).Кажется, что примитивные константы отлично работают в конструкторе.

Я думаю, что это как-то связано с константой, которая не инициализируется в это время (так из файла .cpp).Вы знаете, почему это может произойти?Происходит ли инициализация extern const после полной инициализации программы?

Заранее спасибо

РЕДАКТИРОВАТЬ:

Обратите внимание, что тип stringэто упрощает проблему, поэтому преобразование ее в char не вариант, так как я также заинтересован в том, чтобы иметь и другие не примитивные типы.

Код для минимального грязного примера программы, которая показывает эту проблему:

// constants.h
extern const std::string testString;

// constants.cpp
#include "constants.h"

const std::string testString = "defined!";

// MyClass.h
class MyClass {

public:
    MyClass();
    virtual ~MyClass();
};

// MyClass.cpp
#include "MyClass.h"
#include "constants.h"

MyClass::MyClass() {
   printf("Value of test string: %s\n", testString.c_str());
}

MyClass::~MyClass() {}

// main.cpp
#include "MyClass.h"
#include "constants.h"

MyClass my;            // undefined string (outputs null)

int main(int argc, char** argv) {
    MyClass my;        // defined string
    return 0;
}

РЕДАКТИРОВАТЬ 2:

Решением в этом случае было определение статической встроенной функции в заголовочном файле, как @ Brian и @ LightnessRacesinOrbit предлагается.Они оба внесли свой вклад в окончательный ответ.

Вот код:

inline std::string getTestString() { return "defined!"; }

Это позволяет иметь не constexpr типы в качестве глобальных констант.

1 Ответ

0 голосов
/ 14 ноября 2018

В пределах единицы перевода constants.cpp, testString будет инициализирован перед любой последующей определенной нелокальной переменной. Между единицами перевода мы имеем то, что называется "фиаско статического порядка инициализации"; любая единица перевода, кроме constants.cpp, не может предположить, что testString была инициализирована до тех пор, пока не начнет выполняться main, поэтому, если она пытается прочитать свое значение во время одной из своих нелокальных инициализаций, то она может наблюдать ноль -инициализированный std::string объект с неопределенным поведением.

Мое предложение избежать этой проблемы, которое также является правилом, которому следуют на моем прежнем рабочем месте, заключается в том, что если вам нужны глобальные константы, задайте их constexpr, если это возможно, и очень осторожно относитесь к любым не constexpr глобальные переменные. std::string не constexpr (пока), но старомодный массив char может работать:

// constants.h
inline constexpr char testString[] = "defined!";

// constants.cpp
// no need to define `testString` here!
...