Ключевое слово static
имеет несколько значений в C ++, которое мне кажется очень запутанным, и я никогда не могу думать о том, как оно на самом деле должно работать.
Из того, что я понимаю, есть static
длительность хранения, что означает, что она длится в течение всей жизни программы в случае глобального, но когда вы говорите о локальном, это означает, что он по умолчанию инициализируется нулем.
Стандарт C ++ говорит это для членов класса данных с ключевым словом static
:
3.7.1 Статическая продолжительность хранения [basic.stc.static]
3 Ключевое слово static может использоваться для объявления локальной переменной со статической продолжительностью хранения.
4 Ключевое слово static, примененное к члену данных класса в определении класса, дает длительность хранения статического члена данных.
Что это значит с локальной переменной ? Это локальная переменная функции? Потому что есть также то, что когда вы объявляете функцию локальной так, static
что она инициализируется только один раз, при первом входе в эту функцию.
Это также говорит только о продолжительности хранения в отношении учеников, а как насчет того, чтобы это было не специфично для экземпляра, это тоже свойство static
no? Или это продолжительность хранения?
А как насчет случая с static
областью действия файла? Все ли глобальные переменные по умолчанию имеют статическую продолжительность хранения? Следующее (из раздела 3.7.1), кажется, указывает на это:
1 Все переменные, которые не имеют динамической длительности хранения, не имеют длительности хранения потоков и не являются локальными, имеют статическую длительность хранения. Хранение для этих объектов должно продолжаться в течение всей программы (3.6.2, 3.6.3)
Какое static
отношение имеет связь с переменной?
Это целое static
ключевое слово совершенно сбивает с толку, может кто-то прояснить различные варианты использования английского языка и сказать мне, когда нужно инициализировать static
ученика?
Ответы:
Переменные:
static
переменные существуют для «времени жизни» единицы перевода, в которой она определена , и:constexpr
. Что-нибудь еще, и в результате вы получите отдельную переменную в каждой единице перевода, что сумасшедшая путаница)static
, но могут быть адресованы как из класса, так и из экземпляра (напримерstd::string::npos
). [Примечание: вы можете объявить статические члены в классе, но обычно они все равно должны быть определены в модуле перевода (файл cpp), и поэтому в каждом классе есть только один]местоположения как код:
Перед выполнением какой-либо функции в модуле перевода (возможно, после
main
начала выполнения) переменные со статической продолжительностью хранения (область пространства имен) в этом модуле перевода будут «инициализированы константой» (constexpr
где это возможно, или нулем в противном случае), а затем Местные жители должным образом «динамически инициализируются» в том порядке, в котором они определены в модуле перевода (для подобных вещейstd::string="HI";
это не такconstexpr
). Наконец, локальные статические функции будут инициализированы, когда в первый раз выполнение «достигнет» строки, где они объявлены. Всеstatic
переменные уничтожаются в обратном порядке инициализации.Самый простой способ сделать все это правильно - это сделать все статические переменные, которые не
constexpr
инициализированы, в статические локальные функции, что гарантирует, что все ваши статические / глобальные переменные инициализируются должным образом, когда вы пытаетесь использовать их независимо от того, что, таким образом, предотвращая статическую инициализацию заказать фиаско .Будьте осторожны, потому что, когда спецификация говорит, что переменные области пространства имен по умолчанию имеют «статическую длительность хранения», они означают бит «время жизни единицы перевода», но это не означает, что к нему нельзя получить доступ вне файла.
функции
Значительно более простой,
static
часто используется как функция-член класса, и очень редко используется для отдельно стоящей функции.Статическая функция-член отличается от обычной функции-члена тем, что ее можно вызывать без экземпляра класса, и, поскольку она не имеет экземпляра, она не может получить доступ к нестатическим членам класса. Статические переменные полезны, когда вы хотите иметь функцию для класса, который определенно не ссылается ни на какие элементы экземпляра, или для управления
static
переменными-членами.static
Свободная функция означает , что функция не будет называться любым другим блоком перевода, и , таким образом линкер может игнорировать его полностью. Это имеет небольшое количество целей:static void log(const char*) {}
в каждый файл cpp, и каждый из них может войти по-своему.источник
classname::
область действия. Статические функции-члены класса похожи на глобальные функции, но ограничены классом, или похожи на обычные члены, но безthis
(это не выбор - эти два должны быть эквивалентны).namespace A { static int x; }
, что означает внутреннюю связь и сильно отличается от поведения членов данных статического класса .Статическая продолжительность хранения означает, что переменная находится в одном и том же месте в памяти в течение всего времени жизни программы.
Связь является ортогональной к этому.
Я думаю, что это самое важное различие, которое вы можете сделать. Понимать это и все остальное, а также помнить это, должно быть легко (не обращаясь непосредственно к @Tony, но к тому, кто бы мог прочитать это в будущем).
Ключевое слово
static
может использоваться для обозначения внутренней связи и статического хранилища, но по сути они разные.Да. Независимо от того, когда переменная инициализируется (при первом вызове функции и когда путь выполнения достигает точки объявления), она будет находиться в одном и том же месте в памяти на протяжении всей жизни программы. В этом случае
static
дает статическое хранилище.Да, все глобальные переменные по определению имеют статическую продолжительность хранения (теперь, когда мы выяснили, что это значит). Но переменные в пространстве имен не объявляются
static
, потому что это дало бы им внутреннюю связь, поэтому переменная на единицу перевода.Это дает внутреннюю связь переменных пространства имен. Это дает членам и локальным переменным статическую продолжительность хранения.
Давайте расширим все это:
Определенно, если вы не знакомы с этим. :) Стараясь не добавлять новые ключевые слова в язык, комитет повторно использовал это, IMO, для этого - путаница. Он используется для обозначения разных вещей (я бы сказал, возможно, противоположных вещей).
источник
static int x
в области имен, это дает нестатическое хранилище?Чтобы прояснить вопрос, я бы предпочел классифицировать использование ключевого слова static в трех разных формах:
(А). переменные
(В). функции
(С). переменные-члены / функции классов
объяснение следует ниже для каждого из подзаголовков:
(A) «статическое» ключевое слово для переменных
Это может быть немного сложно, однако, если объяснить и правильно понять, это довольно просто.
Чтобы объяснить это, во-первых, действительно полезно узнать о области действия, продолжительности и связях переменных, без которых вещи всегда трудно увидеть сквозь мутную концепцию staic ключевого слова.
1. Область действия : определяет, где в файле доступна переменная. Он может быть двух типов: (i) локальный или блочный . (ii) Глобальная сфера
2. Длительность : определяет, когда переменная создается и уничтожается. Опять же, он бывает двух типов: (i) Автоматическая продолжительность хранения (для переменных, имеющих локальную или блочную область видимости). (ii) Статическая продолжительность хранения (для переменных, имеющих глобальную область или локальные переменные (в функции или в блоке кода) со статическим спецификатором).
3. Связывание : определяет, может ли переменная быть доступна (или связана) в другом файле. Опять же (и, к счастью) это бывает двух типов: (i) Внутренняя связь (для переменных, имеющих блочную область и глобальную область действия / область действия файла / глобальную область имен) (ii) Внешняя связь (для переменных, имеющих значение только для глобальной области действия / области действия файла /) Область глобального пространства имен)
Давайте рассмотрим пример ниже для лучшего понимания простых глобальных и локальных переменных (без локальных переменных со статической длительностью хранения):
Теперь приходит концепция Linkage. Когда глобальная переменная, определенная в одном файле, предназначена для использования в другом файле, связь с переменной играет важную роль.
Связывание глобальных переменных задается ключевыми словами: (i) статическая и (ii) внешняя
(Теперь вы получите объяснение)
Ключевое слово static может применяться к переменным с локальной и глобальной областью действия, и в обоих случаях они означают разные вещи. Сначала я объясню использование ключевого слова «static» в переменных с глобальной областью действия (где я также поясню использование ключевого слова «extern»), а позже - для тех, которые имеют локальную область действия.
1. Статическое ключевое слово для переменных с глобальной областью видимости
Глобальные переменные имеют статическую длительность, то есть они не выходят за рамки, когда заканчивается конкретный блок кода (например, main ()), в котором он используется. В зависимости от связывания к ним можно получить доступ либо только в том же файле, в котором они объявлены (для статической глобальной переменной), либо вне файла, даже вне файла, в котором они объявлены (глобальные переменные типа extern)
В случае, когда глобальная переменная имеет спецификатор extern, и если к этой переменной обращаются вне файла, в котором она была инициализирована, она должна быть объявлена вперед в файле, где она используется, точно так же, как функция должна быть вперед объявляется, если его определение находится в файле, отличном от того, где он используется.
Напротив, если глобальная переменная имеет ключевое слово static, ее нельзя использовать в файле, за пределами которого она была объявлена.
(см. пример ниже для пояснения)
например:
main3.cpp
теперь любая переменная в c ++ может быть как константной, так и неконстантной, и для каждой «константности» мы получаем два случая связи по умолчанию с ++, в случае, если ни одна не указана:
(i) Если глобальная переменная не является константной, по умолчанию ее связь является внешней , то есть к неконстантной глобальной переменной можно получить доступ в другом файле .cpp путем предварительного объявления с использованием ключевого слова extern (другими словами, неконстантной глобальной переменные имеют внешнюю связь (со статической продолжительностью, конечно)). Также избыточное использование ключевого слова extern в исходном файле, в котором оно было определено. В этом случае, чтобы сделать неконстантную глобальную переменную недоступной для внешнего файла, используйте спецификатор «static» перед типом переменной .
(ii) Если глобальная переменная является const, ее связывание по умолчанию является статическим , то есть глобальная переменная const не может быть доступна в файле, отличном от того, где она определена (другими словами, глобальные переменные const имеют внутреннюю связь (со статической продолжительностью) конечно)). Также использование статического ключевого слова для предотвращения доступа к глобальной переменной const в другом файле является излишним. Здесь, чтобы глобальная переменная const имела внешнюю связь, используйте спецификатор extern перед типом переменной
Вот сводка для глобальных переменных области с различными связями
Далее мы исследуем, как ведут себя вышеупомянутые глобальные переменные при доступе в другом файле.
2. Статическое ключевое слово для переменных с локальной областью действия
Обновления (август 2019 г.) статического ключевого слова для переменных в локальной области видимости
Это далее может быть разделено на две категории:
(i) статическое ключевое слово для переменных в функциональном блоке и (ii) статическое ключевое слово для переменных в неназванном локальном блоке.
(i) статическое ключевое слово для переменных в функциональном блоке.
Ранее я упоминал, что переменные с локальной областью действия имеют автоматическую длительность, то есть они начинают существовать при вводе блока (будь то нормальный блок, будь то функциональный блок) и перестают существовать, когда блок заканчивается, короче говоря, переменные с локальной областью действия имеют автоматическую длительность, а автоматические переменные длительности (и объекты) не имеют связи, означая, что они не видны вне блока кода.
Если статический спецификатор применяется к локальной переменной в функциональном блоке, он меняет продолжительность переменной с автоматического на статический, а его срок службы равен всей продолжительности программы, что означает, что она имеет фиксированное расположение в памяти, и ее значение инициализируется только один раз перед запуском программы, как указано в справочнике cpp (инициализация не должна быть перепутана с присваиванием)
Давайте посмотрим на пример.
Глядя на приведенный выше критерий для статических локальных переменных и статических глобальных переменных, можно задаться вопросом, в чем может быть разница между ними. Хотя глобальные переменные доступны в любой точке кода (как в разных, так и в разных единицах перевода в зависимости от const -ness и extern -ness), статическая переменная, определенная в функциональном блоке, недоступна напрямую. Переменная должна быть возвращена значением функции или ссылкой. Давайте продемонстрируем это на примере:
Более подробное объяснение о выборе статической глобальной и статической локальной переменной можно найти в этом потоке stackoverflow
(ii) статическое ключевое слово для переменных в неназванном локальном блоке.
Статические переменные в локальном блоке (не функциональном блоке) не могут быть доступны вне блока, как только локальный блок выходит из области видимости. Никаких предостережений к этому правилу.
В C ++ 11 введено ключевое слово,
constexpr
которое гарантирует оценку выражения во время компиляции и позволяет компилятору оптимизировать код. Теперь, если значение статической константной переменной в области видимости известно во время компиляции, код оптимизируется аналогично тому, с которымconstexpr
. Вот небольшой примерЯ рекомендую читателям также посмотреть разницу между переменными в потоке stackoverflow
constexpr
иstatic const
для них . На этом мое объяснение ключевого слова static применяется к переменным.B. ключевое слово static для функций
в терминах функций ключевое слово static имеет прямое значение. Здесь это относится к связыванию функции. Обычно все функции, объявленные в файле cpp, по умолчанию имеют внешнюю связь, то есть функция, определенная в одном файле, может использоваться в другом файле cpp путем предварительного объявления.
использование статического ключевого слова до объявления функции ограничивает его связь с внутренним , то есть статическая функция не может использоваться внутри файла вне ее определения.
C. Staitc Ключевое слово, используемое для переменных-членов и функций классов
1. «статическое» ключевое слово для переменных-членов классов
Я начну прямо с примера здесь
В этом примере статическая переменная m_designNum сохраняет свое значение, и эта единственная закрытая переменная-член (потому что она статическая) является общей для всех переменных типа объекта DesignNumber.
Также как и другие переменные-члены, статические переменные-члены класса не связаны ни с одним объектом класса, что демонстрируется печатью anyNumber в основной функции.
const против неконстантных статических переменных-членов в классе
(i) статические переменные-члены неконстантного класса. В предыдущем примере статические члены (как открытые, так и частные) были неконстантными. Стандарт ISO запрещает инициализацию неконстантных статических элементов в классе. Следовательно, как и в предыдущем примере, они должны быть инициализированы после определения класса, с оговоркой, что статическое ключевое слово должно быть опущено
(ii) const-статические переменные-члены класса это просто и соответствует соглашению об инициализации других переменных-членов const, то есть постоянные статические переменные-члены класса могут быть инициализированы в точке объявления, и они могут быть инициализированы в конце объявления класса с одним предупреждением о том, что ключевое слово const необходимо добавить к статическому члену при инициализации после определения класса.
Однако я бы порекомендовал инициализировать статические переменные-члены const в точке объявления. Это соответствует стандартному соглашению C ++ и делает код более чистым
Дополнительные примеры статических переменных-членов в классе можно найти по следующей ссылке с learncpp.com http://www.learncpp.com/cpp-tutorial/811-static-member-variables/
2. «статическое» ключевое слово для функции-члена классов
Как переменные-члены классов могут быть статическими, так и функции-члены классов. Обычные функции-члены классов всегда связаны с объектом типа класса. Напротив, статические функции-члены класса не связаны ни с одним объектом класса, т. Е. У них нет * этого указателя.
Во-вторых, поскольку статические функции-члены класса не имеют * этого указателя, их можно вызывать с помощью оператора разрешения имени и области видимости в главной функции (ClassName :: functionName ();)
В-третьих, статические функции-члены класса могут обращаться только к статическим переменным-членам класса, поскольку нестатические переменные-члены класса должны принадлежать объекту класса.
Дополнительные примеры статических функций-членов в классе можно найти по следующей ссылке с learncpp.com.
http://www.learncpp.com/cpp-tutorial/812-static-member-functions/
источник
struct Foo{static const std::string name = "cpp";};
, ошибка,name
должна быть определена вне класса; с встроенными переменными, внедренными в c ++ 17, можно кодировать:struct Foo{static inline const std::string name = "cpp";};
2) Доступ к открытым статическим членам / функциям-членам можно получить по имени класса с помощью оператора разрешения области, а также по экземпляру с оператором точки (например: instance.some_static_method ())Это на самом деле довольно просто. Если вы объявляете переменную как статическую в области действия функции, ее значение сохраняется между последовательными вызовами этой функции. Так:
будет показывать
678
вместо666
, потому что он запоминает увеличенное значение.Что касается статических членов, они сохраняют свое значение в экземплярах класса. Итак, следующий код:
выведет 4, потому что first.a и second.a по сути являются одной и той же переменной. Что касается инициализации, см. Этот вопрос.
источник
Когда вы объявляете
static
переменную в области видимости файла, тогда эта переменная доступна только в этом конкретном файле (технически, модуль перевода *, но давайте не будем слишком усложнять это). Например:a.cpp
b.cpp
main.cpp:
Для локальной переменной
static
означает, что переменная будет инициализирована нулем и сохранит свое значение между вызовами:Для переменных класса это означает, что существует только один экземпляр этой переменной, который является общим для всех членов этого класса. В зависимости от прав доступа к переменной можно обращаться извне класса, используя его полное имя.
Пометка функции, не относящейся к классу as,
static
делает функцию доступной только из этого файла и недоступной из других файлов.a.cpp
b.cpp
Для функций-членов класса их маркировка
static
означает, что функцию не нужно вызывать для конкретного экземпляра объекта (т. Е. У нее нетthis
указателя).источник
Статические переменные совместно используются каждым экземпляром класса, а не каждому классу, имеющему собственную переменную.
Каждый экземпляр MyClass имеет свой собственный myVar, но имеет один и тот же myStaticVar. На самом деле вам даже не нужен экземпляр MyClass для доступа к myStaticVar, и вы можете получить к нему доступ вне класса следующим образом:
При использовании внутри функции в качестве локальной переменной (а не в качестве переменной-члена класса) ключевое слово static делает что-то другое. Это позволяет вам создавать постоянные переменные, не давая глобальной области видимости.
Это глобальная переменная с точки зрения постоянства ... но не глобальная по объему / доступности.
Вы также можете иметь статические функции-члены. Статические функции в основном не являются членами, но находятся внутри пространства имен имени класса и имеют частный доступ к членам класса.
Когда вы вызываете функцию-член, появляется скрытый параметр с именем 'this', который является указателем на экземпляр класса, вызывающего функцию. Статические функции-члены не имеют этого скрытого параметра ... они могут вызываться без экземпляра класса, но также не могут получить доступ к нестатическим переменным-членам класса, поскольку у них нет указателя «this» для работы. Они не вызываются ни для какого конкретного экземпляра класса.
источник
myStaticVar
нужно также определить. Конечно, важно отметить, что, отвечая на вопрос о семантикеstatic
ключевого слова, вы не думаете?Я не программист на C, поэтому я не могу дать вам информацию об использовании static в программе на C должным образом, но когда дело доходит до объектно-ориентированного программирования, static в основном объявляет переменную или функцию или класс одинаковыми. на протяжении всей жизни программы. Взять к примеру.
Когда вы создаете этот класс в своем Main, вы делаете что-то вроде этого.
Эти два экземпляра класса полностью отличаются друг от друга и работают независимо друг от друга. Но если бы вы воссоздали класс А вот так.
Вернемся к основному снова.
Тогда a1 и a2 будут совместно использовать одну и ту же копию int x, в результате чего любые операции над x в a1 будут напрямую влиять на операции x в a2. Так что, если бы я должен был сделать это
Оба экземпляра класса A имеют общие статические переменные и функции. Надеюсь, что это ответ на ваш вопрос. Мои ограниченные знания C позволяют мне сказать, что определение функции или переменной как статического означает, что для файла видно, что функция или переменная определена как статическая. Но на этот вопрос лучше бы ответил парень из C, а не я. C ++ позволяет как C, так и C ++ объявлять ваши переменные как статические, потому что они полностью обратно совместимы с C.
источник
Да - Неглобальный, такой как локальная переменная функции.
Правильно.
то есть, все экземпляры
R
долиint R::a
-int R::a
никогда не копируются.Эффективно глобальный, который имеет конструктор / деструктор, где это уместно - инициализация не откладывается до доступа.
Для функции локальной она является внешней. Доступ: он доступен для функции (если, конечно, вы ее не вернете).
Для класса это внешнее. Доступ: применяются стандартные спецификации доступа (открытый, защищенный, частный).
static
также может указывать внутреннюю связь, в зависимости от того, где она объявлена (файл / пространство имен).У него слишком много целей в C ++.
Он автоматически инициализируется раньше,
main
если он загружен и имеет конструктор. Это может звучать как хорошая вещь, но порядок инициализации в значительной степени находится вне вашего контроля, поэтому сложную инициализацию становится очень трудно поддерживать, и вы хотите минимизировать это - если у вас есть статический тип, то функция локального масштабирования гораздо лучше масштабируется по библиотекам и проекты. Что касается данных со статической продолжительностью хранения, вы должны попытаться минимизировать этот дизайн, особенно если он изменчив (глобальные переменные). «Время» инициализации также варьируется по ряду причин - у загрузчика и ядра есть несколько хитростей, позволяющих минимизировать использование памяти и отложить инициализацию в зависимости от данных.источник
Статический объект: мы можем определить статические члены класса, используя ключевое слово static. Когда мы объявляем член класса статическим, это означает, что независимо от того, сколько объектов класса создано, существует только одна копия статического члена.
Статический член является общим для всех объектов класса. Все статические данные инициализируются нулем при создании первого объекта, если нет других инициализаций. Мы не можем поместить его в определение класса, но его можно инициализировать вне класса, как это сделано в следующем примере, путем повторного выделения статической переменной с помощью оператора разрешения области :: для определения, к какому классу он принадлежит.
Давайте попробуем следующий пример, чтобы понять концепцию статических членов данных:
Когда приведенный выше код компилируется и выполняется, он дает следующий результат:
Статические члены-функции. Объявляя член функции как статический, вы делаете его независимым от какого-либо конкретного объекта класса. Статическая функция-член может быть вызвана, даже если объекты класса не существуют, и к статическим функциям можно обращаться, используя только имя класса и оператор разрешения области ::.
Статическая функция-член может получить доступ только к статическим данным-членам, другим статическим функциям-членам и любым другим функциям вне класса.
Статические функции-члены имеют область видимости класса, и у них нет доступа к указателю this класса. Вы можете использовать статическую функцию-член, чтобы определить, были ли созданы некоторые объекты класса.
Давайте попробуем следующий пример, чтобы понять концепцию статических членов функции:
Когда приведенный выше код компилируется и выполняется, он дает следующий результат:
источник