C можно ли отложить инициализацию постоянного статического члена?

#c #qt #static-initialization

#c #qt #статическая инициализация

Вопрос:

Я использую Qt, но это общий вопрос C . Мой случай прост, у меня есть класс Constants с постоянным статическим членом, который я хочу, чтобы он был инициализирован после выполнения определенных вызовов функций.

Constants.h

 #ifndef CONSTANTS_H
#define CONSTANTS_H

class Constants
{
public:

    static const char* const FILE_NAME;
};

#endif // CONSTANTS_H
  

Constants.cpp

 #include "constants.h"
#include <QApplication>

const char* const Constants::FILE_NAME = QApplication::applicationFilePath().toStdString().c_str();
  

main.cpp

 #include <QtGui/QApplication>
#include "mainwindow.h"
#include "constants.h"
#include <QDebug>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    qDebug()<< "name: "<<Constants::FILE_NAME;
    //for those who are unfamiliar with Qt, qDebug just prints out
    return a.exec();
}
  

При компиляции я получил:

QCoreApplication::applicationFilePath: Пожалуйста, сначала создайте экземпляр объекта QApplication

Итак, проблема здесь очевидна. Когда статическая функция QApplication вызывается в Constants.cpp QApplication еще не установлено Qt. Мне нужно как-то подождать, пока QApplication a(argc, argv); строка не будет передана в main.cpp

возможно ли это, и если нет, что еще вы могли бы предложить для преодоления этого?

Спасибо

Комментарии:

1. Не объявлять его как константу? Это определенно не константа, поскольку она зависит от некоторого состояния при запуске приложения.

2. но мне нужно, чтобы он считывался только после его назначения?

3. Я могу ошибаться, но QApplication::applicationFilePath().toStdString() для меня это выглядит как временное, и в этом случае вы сохраняете указатель на недопустимые данные.

4. Например: используйте объект (например, экземпляр класса String), присвоите ему значение NULL и проверьте, равно ли оно NULL (что означает, что он еще не назначен).

5. Вы можете использовать .toAscii() вместо .toStdString().c_str() .

Ответ №1:

Типичное решение:

 #ifndef CONSTANTS_H
#define CONSTANTS_H

class Constants
{
public:

    static const char* const getFILE_NAME();
};

#endif // CONSTANTS_H
  

И в cpp

 #include "constants.h"
#include <QApplication>

const char* const Constants::getFILE_NAME()
{
    static const char* const s_FILE_NAME = QApplication::applicationFilePath().toStdString().c_str();

    return s_FILE_NAME;
}
  

Комментарии:

1. Разве вы не храните указатель на содержимое временной строки? Или toStdString() возвращает ссылку на что-то постоянное?

2. @MikeSeymour: переместить этот комментарий в OP?

3. Хороший ответ, хотя я бы предпочел пространство имен классу только со статическими членами.

4. Думаю, я согласен. Тем не менее, вышесказанное может быть типичным 🙂

Ответ №2:

Один из вариантов — вернуть его из функции, сохранив его в статической переменной. Это будет инициализировано при первом вызове функции.

 char const * const file_name()
{
    // Store the string, NOT the pointer to a temporary string's contents
    static std::string const file_name =
        QApplication::applicationFilePath().toStdString();
    return file_name.c_str();
}
  

Комментарии:

1. Хотя 2 ответа дают одинаковый результат и работают хорошо, ваш ответ кажется более безопасным. Спасибо

2. @ValekHalfHeart: Плохая идея возвращать указатель на автоматический локальный. Этот элемент является статическим, поэтому он все еще будет существовать, когда функция вернется.

3. @MikeSeymour Правильно. Мне это никогда не приходило в голову.