Каков наилучший способ инициализации частного статического члена данных в C ++? Я попробовал это в моем заголовочном файле, но он дает мне странные ошибки компоновщика:
class foo
{
private:
static int i;
};
int foo::i = 0;
Я предполагаю, что это потому, что я не могу инициализировать частного члена вне класса. Так каков лучший способ сделать это?
c++
initialization
static-members
Джейсон Бейкер
источник
источник
inline static int x[] = {1, 2, 3};
. См. En.cppreference.com/w/cpp/language/static#Static_data_membersОтветы:
Объявление класса должно быть в заголовочном файле (или в исходном файле, если он не используется совместно).
Файл: foo.h
Но инициализация должна быть в исходном файле.
Файл: foo.cpp
Если инициализация находится в файле заголовка, то каждый файл, который включает файл заголовка, будет иметь определение статического члена. Таким образом, на этапе компоновки вы получите ошибки компоновщика, так как код для инициализации переменной будет определен в нескольких исходных файлах. Инициализация
static int i
должна выполняться вне какой-либо функции.Примечание: Мэтт Кертис: указывает, что C ++ позволяет упростить выше , если статическая переменная - член имеет сопзЬ типа Int (например
int
,bool
,char
). Затем вы можете объявить и инициализировать переменную-член непосредственно внутри объявления класса в заголовочном файле:источник
Для переменной :
foo.h:
foo.cpp:
Это потому, что
foo::i
в вашей программе может быть только один экземпляр . Это своего рода эквивалентextern int i
в заголовочном файле иint i
в исходном файле.Для константы вы можете поместить значение прямо в объявлении класса:
источник
private
переменные могут быть инициализированы вне Класса здесь, это может быть сделано для нестатических переменных также.Class
не имеет никакого смысла в Cpp.Начиная с C ++ 17, статические члены могут быть определены в заголовке с ключевым словом inline .
http://en.cppreference.com/w/cpp/language/static
«Элемент статических данных может быть объявлен встроенным. Элемент статических данных может быть определен в определении класса и может указывать инициализатор элемента по умолчанию. Для него не требуется определение вне класса:»
источник
Для будущих читателей этого вопроса я хочу отметить, что вам следует избегать того, что предлагает monkey0506 .
Заголовочные файлы предназначены для объявлений.
Заголовочные файлы компилируются один раз для каждого
.cpp
файла, который прямо или косвенно#includes
их использует, а код вне какой-либо функции запускается при инициализации программы раньшеmain()
.Поместив:
foo::i = VALUE;
в заголовок,foo:i
будет присвоено значениеVALUE
(что бы это ни было) для каждого.cpp
файла, и эти назначения будут выполняться в неопределенном порядке (определенном компоновщиком) передmain()
запуском.Что если мы
#define VALUE
будем другим номером в одном из наших.cpp
файлов? Он будет хорошо скомпилирован, и мы не сможем узнать, кто из них победит, пока не запустим программу.Никогда не помещайте исполняемый код в заголовок по той же причине, по которой вы никогда не
#include
используете.cpp
файл.включают в себя охранники (которые, я согласен, вы всегда должны использовать) защищают вас от чего-то другого: один и тот же заголовок косвенно используется
#include
несколько раз при компиляции одного.cpp
файлаисточник
С помощью компилятора Microsoft [1] статические переменные, которые не
int
похожи на другие, также могут быть определены в заголовочном файле, но вне объявления класса, используя специфику Microsoft__declspec(selectany)
.Обратите внимание, что я не говорю, что это хорошо, я просто говорю, что это можно сделать.
[1] В наши дни больше компиляторов, чем MSC,
__declspec(selectany)
- по крайней мере, gcc и clang. Может быть, даже больше.источник
Правильный синтаксис для инициализации переменной, но он должен идти в исходном файле (.cpp), а не в заголовке.
Поскольку это статическая переменная, компилятору необходимо создать только одну ее копию. У вас должна быть строка «int foo: i», где-то в вашем коде, чтобы указать компилятору, куда ее поместить, в противном случае вы получите ошибку ссылки. Если это в заголовке, вы получите копию в каждом файле, который включает заголовок, поэтому получите многозначно определенные ошибки символов от компоновщика.
источник
У меня недостаточно репов здесь, чтобы добавить это в качестве комментария, но IMO - это хороший стиль, чтобы написать заголовки с защитой #include в любом случае, что, как заметил Paranaix несколько часов назад, предотвратило бы ошибку множественного определения. Если вы уже не используете отдельный файл CPP, нет необходимости использовать его только для инициализации статических нецелых элементов.
Я не вижу необходимости использовать отдельный файл CPP для этого. Конечно, вы можете, но нет никаких технических причин, почему вы должны это делать.
источник
#endif // FOO_H
#pragma once
Если вы хотите инициализировать некоторый составной тип (например, строку), вы можете сделать что-то вроде этого:
Поскольку
ListInitializationGuard
статическая переменная внутриSomeClass::getList()
метода, она будет создана только один раз, что означает, что конструктор вызывается один раз. Это изменитinitialize _list
значение, которое вам нужно. Любой последующий вызовgetList
просто вернет уже инициализированный_list
объект.Конечно, вы всегда должны обращаться к
_list
объекту, вызываяgetList()
метод.источник
Шаблон статического конструктора C ++ 11, который работает для нескольких объектов
Одна идиома была предложена по адресу: https://stackoverflow.com/a/27088552/895245, но здесь идет более чистая версия, которая не требует создания нового метода для каждого члена.
main.cpp
GitHub вверх по течению .
Скомпилируйте и запустите:
Смотрите также: статические конструкторы в C ++? Мне нужно инициализировать частные статические объекты
Проверено на Ubuntu 19.04.
C ++ 17 встроенная переменная
Упоминается по адресу: https://stackoverflow.com/a/45062055/895245, но здесь приведен пример запуска нескольких файлов, чтобы сделать его еще более понятным: как работают встроенные переменные?
источник
Вы также можете включить назначение в файл заголовка, если вы используете защиту заголовка. Я использовал эту технику для библиотеки C ++, которую я создал. Еще один способ добиться того же результата - использовать статические методы. Например...
Приведенный выше код имеет «бонус», не требующий CPP / исходный файл. Опять же, метод, который я использую для моих библиотек C ++.
источник
Я следую за идеей от Карла. Мне нравится это, и теперь я использую это также. Я немного изменил обозначения и добавил некоторые функциональные возможности
это выводы
источник
Также работает в файле privateStatic.cpp:
источник
Как насчет
set_default()
метода?Нам нужно будет только использовать
set_default(int x)
метод, и нашаstatic
переменная будет инициализирована.Это не будет противоречить остальным комментариям, фактически оно следует тому же принципу инициализации переменной в глобальной области видимости, но с помощью этого метода мы делаем его явным (и легко видимым для понимания) вместо того, чтобы иметь определение переменной висит там.
источник
Вероятно, возникла проблема с компоновщиком:
Это общая проблема для тех, кто начинает с C ++. Статический член класса должен быть инициализирован в одной единице перевода, т.е. в одном исходном файле.
К сожалению, статический член класса должен быть инициализирован вне тела класса. Это усложняет написание кода только для заголовка, и поэтому я использую совершенно другой подход. Вы можете предоставить свой статический объект через статическую или нестатическую функцию класса, например:
источник
Один из "старых" способов определения констант состоит в замене их на
enum
:Этот способ не требует предоставления определения и избегает создания постоянного lvalue , что может избавить вас от некоторых головных болей, например, когда вы случайно используете его ODR .
источник
Я просто хотел упомянуть кое-что немного странное для меня, когда я впервые столкнулся с этим.
Мне нужно было инициализировать закрытый статический член данных в шаблонном классе.
в .h или .hpp это выглядит примерно так, чтобы инициализировать статический член данных класса шаблона:
источник
Это служит вашей цели?
источник