Допустим, я создаю:
class Hello {
public:
int World(int in)
{
static int var = 0; // <<<< This thing here.
if (in >= 0) {
var = in;
} else {
cout << var << endl;
}
}
};
Теперь, если я это сделаю:
Hello A;
Hello B;
A.World(10);
A.World(-1);
B.World(-1);
Я получаю «10», за которым следует еще «10». Значение локальной переменной метода только что перешло от одного экземпляра класса к другому.
Это не удивительно - технически методы - это просто функции со скрытым параметром this
, поэтому статическая локальная переменная должна вести себя так же, как в обычных функциях. Но это гарантировано ? Является ли это поведением, предписываемым стандартом, или это просто счастливый побочный продукт того, как компилятор обрабатывает методы? Другими словами - безопасно ли использовать такое поведение? (... сверх стандартного риска сбить с толку непривычного ...)
4 ответа
Да. Не имеет значения, является ли функция [нестатическим] членом класса или нет, гарантируется наличие только одного экземпляра его статических переменных.
Правильное техническое объяснение таких переменных состоит в том, что это объекты с static duration
и internal linkage
- и, таким образом, эти имена действуют до выхода из программы, и все экземпляры этого имени относятся к одному и тому же объекту.
К правильному ответу можно добавить только одно. Если ваш класс был шаблонным, то экземпляр var
будет совместно использоваться только объектами одного и того же типа экземпляра. Итак, если у вас было:
template<typename C>
class Hello {
public:
int World(int in)
{
static int var = 0; // <<<< This thing here.
if (in >= 0) {
var = in;
} else {
cout << var << endl;
}
}
};
А потом:
Hello<int> A;
Hello<int> B;
Hello<unsigned> C;
A.World(10);
A.World(-1);
B.World(-1);
C.World(-1);
Тогда окончательный результат будет «0», а не «10», потому что экземпляр Hello<unsigned>
будет иметь свою собственную копию var
.
Если мы говорим о компиляторе Windows, это гарантировано
https://msdn.microsoft.com/en-us/library/y5f6w579.aspx
В следующем примере показана локальная переменная, объявленная статической в функции-члене. Статическая переменная доступна для всей программы; все экземпляры типа используют одну и ту же копию статической переменной.
Они используют пример, очень похожий на ваш.
Я не знаю о GCC
Да, это гарантировано. Теперь, чтобы ответить на вопрос "Есть ли риск совместного использования локальной статической переменной метода между экземплярами?" это могло быть немного менее просто. Могут существовать потенциальные риски при инициализации и использовании переменной, и эти риски специфичны для переменных, локальных для метода (в отличие от переменных класса).
Для инициализации соответствующая часть в стандарте - 6.7 / 4 [stmt.dcl]:
Динамическая инициализация переменной области блока со статической продолжительностью хранения (3.7.1) или продолжительностью хранения потока (3.7.2) выполняется при первом прохождении управления через ее объявление; такая переменная считается инициализированной после завершения ее инициализации. Если инициализация завершается выдачей исключения, инициализация не завершена, поэтому она будет повторена, когда в следующий раз элемент управления войдет в объявление. Если элемент управления входит в объявление одновременно с инициализацией переменной, параллельное выполнение должно ждать завершения инициализации. Если элемент управления повторно входит в объявление рекурсивно во время инициализации переменной, поведение не определено.
В простых случаях все должно работать должным образом. Когда создание и инициализация переменной более сложны, в этом случае будут риски. Например, если конструктор бросает, у него будет возможность бросить снова при следующем вызове. Другой пример - рекурсивная инициализация, которая является неопределенным поведением.
Другой возможный риск - это эффективность метода. Компилятору потребуется реализовать механизм, обеспечивающий совместимую инициализацию переменной. Это зависит от реализации и вполне может быть блокировкой для проверки того, инициализирована ли переменная, и эта блокировка может выполняться каждый раз при вызове метода. Когда это происходит, это может существенно отрицательно сказаться на производительности.
Похожие вопросы
Новые вопросы
c++
C++ — это язык программирования общего назначения. Изначально он разрабатывался как расширение C и имел аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде, который будет скомпилирован с помощью компилятора C++. Используйте тег версии для вопросов, связанных с конкретной стандартной версией [C++11], [C++14], [C++17], [C++20] или [C++23]. и т.д.