константные переменные в заголовочном файле и фиаско статической инициализации - PullRequest
14 голосов
/ 26 января 2011

После прочтения множества вопросов, касающихся инициализации статических переменных, я все еще не уверен, как это применимо к const переменным на уровне пространства имен.

У меня есть вид следующего кода в заголовке файле config.h, созданном сценарием сборки:

static const std::string path1 = "/xyz/abc";
static const std::string path2 = "/etc";

Согласно тому, что я прочитал, ключевое слово static не обязательно, даже не рекомендуется здесь.

Мой вопрос: Является ли приведенный выше код склонным к фиаско статической инициализации?

Если у меня есть следующее в заголовке file myclass.h:

class MyClass
{
public:
    MyClass(const std::string& str) : m_str(str) {}
    std::string Get() const { return m_str; }

private:
    std::string m_str;
}

const MyClass myclass1("test");

Это создаст проблемы со статической инициализацией?

Если я правильно понял, из-за const переменных, имеющих внутреннюю связь, проблем не должно быть в обоих случаях?

Редактировать: (из-за ответа дрибей)

Может быть, я должен упомянуть, что меня интересуют варианты использования, такие как:

В main.cpp:

#include <config.h>
#include <myclass.h>

std::string anotherString(path1 + myclass1.Get());

int main()
{
    ...
}

Еще один вопрос, касающийся этого варианта использования: оптимизирует ли компилятор path2 в этом случае?

Ответы [ 4 ]

12 голосов
/ 26 января 2011

Ваше первое определение помещает path1 в каждую единицу компиляции, которая включает config.h.Чтобы избежать этого, не определяйте переменные в заголовочных файлах.Обычно вы объявляете переменные в заголовке как extern:

extern const std::string path1;
extern const MyClass myclass1;

и определяете их в единицах перевода, например, config.cpp:

const std::string path1 = "/xyz/abc";
const MyClass myclass1("test");

Иногда вам нужнопостоянная переменная, которую можно использовать только из одной единицы перевода.Затем вы можете объявить эту переменную в области видимости файла как static.

static const std::string path1 = "/xyz/abc";

static больше не считается устаревшей.static и extern иногда подразумеваются, но я всегда забываю, где и как, поэтому я обычно указываю их явно для всех переменных уровня пространства имен.

9 голосов
/ 27 января 2011

Я пытался получить необходимую информацию прямо из документа C ++ 03 Standard. Вот что я нашел:

Относительно деклараций const static:

Согласно разделу 3.5.3 объекты, определенные на уровне пространства имен и объявленные const, имеют по умолчанию внутреннюю связь . static также объявляет объект уровня пространства имен для внутренней связи, поэтому нет необходимости объявлять объект static const.

Также согласно Приложению D.2

Использование статического ключевого слова не рекомендуется при объявлении объектов в область имен (см. 3.3.5).

По поводу фиаско статической инициализации:

Поскольку переменные определены в заголовочном файле, они всегда определяются перед любыми другими статическими объектами, использующими их.

Из раздела 3.6.2.1:

Объекты со статической продолжительностью хранения определяется в области имен пространства в том же блок перевода и динамически инициализируется должен быть инициализирован в порядок, в котором их определение появляется в блоке перевода.

Ответ 1: Это означает, что передача переменных в конструктор статического объекта должна быть в порядке.

Ответ 2: Однако проблема может возникнуть, если на переменные ссылаются из не встроенного конструктора статического объекта:

Ни в разделе 3.6.2.1, ни в 3.6.2.3 не указано, в каком порядке статические объекты в разных единицах компиляции инициализируются , если динамическая инициализация выполняется перед первым оператором main.

Обратите внимание на следующее:

// consts.h
#include <string>

const std::string string1 = "ham";
const std::string string2 = "cheese";

// myclass.h
#include <string>

class MyClass
{
public:
    MyClass();
    MyClass(std::string str);
    std::string Get() { return memberString; }
private:
    std::string memberString;
}

// myclass.cpp
#include "consts.h"
#include "myclass.h"

MyClass::MyClass() : memberString(string1) {}

MyClass::MyClass(std::string str) : memberString(str) {}

// main.cpp
#include <iostream>
#include "consts.h"
#include "myclass.h"

MyClass myObject1;
MyClass myObject2(string2);

using namespace std;

int main()
{
    cout << myObject1.Get(); // might not print "ham"
    cout << myObject2.Get(); // will always print "cheese"
}

Поскольку myclass.cpp имеет свою собственную копию переменных const, они могут не инициализироваться при вызове MyClass::MyClass().

Так что да, переменные const, определенные в заголовочных файлах, могут использоваться таким образом, который склонен к статической инициализации фиаско

Насколько я понимаю, это относится только к переменным, не требующим статической инициализации:

Из стандарта C ++ 03, раздел 3.6.2.1:

Объекты типов POD (3.9) со статическими продолжительность хранения инициализируется с константные выражения (5.19) должны быть инициализируется перед любой динамикой инициализация происходит.

8 голосов
/ 26 января 2011

То, что называется фиаско статической инициализации, является проблемой, когда одна переменная уровня пространства имен зависит от значения, назначенного другой переменной уровня пространства имен, которая могла бы быть инициализирована или нет ранее.В ваших двух примерах такой зависимости нет и не должно быть никаких проблем.

Это, с другой стороны, подвержено такому типу ошибки:

// header.h
extern const std::string foo;

// constant.cpp
const std::string foo( "foo" );

// main.cpp
#include "header.h"
const std::string foobar( foo+"bar" );
int main() {
   std::cout << foobar << std::endl;
}

Нетгарантируйте, что foo будет инициализирован до foobar, даже если оба являются постоянными.Это означает, что поведение программы не определено, и оно вполне может вывести «foobar», «bar» или die.

2 голосов
/ 26 января 2011

Статическая инициализация фиаско относится к статическим переменным, которые зависят друг от друга .Простое определение некоторых static const переменных не будет источником проблем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...