Почему вы _have_ инициализировать статическую переменную-член C ++? - PullRequest
9 голосов
/ 04 ноября 2010

Я знаю, что вы обычно инициализируете статическую переменную-член из файла .cpp.Но мой вопрос: почему у вас есть до?

Вот пример: </p> <pre><code>#include <vector> using namespace std; class A { public: static vector<int> x; }; main() { int sz = A::x.size(); }

Это дает ошибку компилятора: undefined reference to 'A::x'

Однако, это: </p> <pre><code>#include <vector> using namespace std; class A { public: static vector<int> x; }; // Initialize static member vector<int> A::x; main() { int sz = A::x.size(); }

компилируется и работает нормально.

IЯ могу понять, инициализировал ли я вектор с помощью чего-то другого, кроме конструктора по умолчанию, но это не так.Я просто хочу создать вектор размером 0.Конечно, любые статические члены должны быть выделены памяти при инициализации программы, так почему же компилятор не использует конструктор по умолчанию?

Ответы [ 4 ]

16 голосов
/ 04 ноября 2010

Это не об инициализации , это о определении . Или, точнее: это информация о том, какой модуль компиляции (.cpp) будет содержать объект (который должен быть уникально определен ГДЕ-ТО)

Итак, нужно просто поместить определение где-нибудь , в уникальном месте , то есть в cpp, чтобы компилятор знал, что когда вызывается статический объект класса это определено там и больше нигде. (если вы попытаетесь определить вашу статическую в заголовке, каждый cpp, включая этот заголовок, будет иметь определение, что делает невозможным знать, где оно должно быть определено - и инициализируется вручную, если это требуется для вашего использования) .

9 голосов
/ 04 ноября 2010

Вы смотрите на это с точки зрения одной единицы компиляции.

Но язык должен предполагать, что потенциально может быть несколько блоков компиляции. Итак, в каком модуле компиляции создается статический объект? По сути, компилятору не разрешено принимать такое решение, и инженер должен принимать решение.

3 голосов
/ 04 ноября 2010

undefined reference to 'A::x' не является ошибкой компилятора;это ошибка компоновщика.Это означает, что определение A::x не может быть найдено ни в одном из блоков перевода, которые связаны вместе, чтобы сформировать вашу программу.Переменные статического члена имеют внешнюю связь и должны быть определены ровно в одной единице перевода.Все, что имеет внешнюю связь, не будет иметь определения, сгенерированного компилятором, если вы его не напишите.

2 голосов
/ 04 ноября 2010

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

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

...