Статические переменные в функциях-членах

Может кто-нибудь объяснить, как статические переменные в функциях-членах работают в C++.

Учитывая следующий класс:

class A {
   void foo() {
      static int i;
      i++;
   }
}

Если я объявляю несколько экземпляров A, увеличивает ли вызов foo() в одном экземпляре статическую переменную i во всех экземплярах? Или только тот, который был вызван?

Я предполагал, что у каждого экземпляра будет своя собственная копия i, но пошаговое выполнение некоторого кода, который я имею, указывает на обратное.

Ответ 1

Так как class A - это неклассический класс, а A::foo() - функция без шаблона. В программе будет только одна копия static int i.

Любой экземпляр объекта A будет влиять на тот же i, а время жизни i останется вне программы. Чтобы добавить пример:

A o1, o2, o3;
o1.foo(); // i = 1
o2.foo(); // i = 2
o3.foo(); // i = 3
o1.foo(); // i = 4

Ответ 2

Ключевое слово static, к сожалению, имеет несколько разных несвязанных значений в С++

  • При использовании для членов данных это означает, что данные выделены в классе, а не в экземплярах.

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

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

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

В вашем коде ключевое слово static используется со значением 2 и не имеет ничего общего с классами или экземплярами... это переменная функции , и будет только одна копия его.

Как правильно iammilind сказал, однако, может быть несколько экземпляров этой переменной, если функция была функцией шаблона (потому что в этом случае действительно сама функция может присутствовать во многих разных экземплярах в программе). Даже в этом случае классы и примеры курсов не имеют значения... см. Следующий пример:

#include <stdio.h>

template<int num>
void bar()
{
    static int baz;
    printf("bar<%i>::baz = %i\n", num, baz++);
}

int main()
{
    bar<1>(); // Output will be 0
    bar<2>(); // Output will be 0
    bar<3>(); // Output will be 0
    bar<1>(); // Output will be 1
    bar<2>(); // Output will be 1
    bar<3>(); // Output will be 1
    bar<1>(); // Output will be 2
    bar<2>(); // Output will be 2
    bar<3>(); // Output will be 2
    return 0;
}

Ответ 3

Статические переменные внутри функций

  • Статическая переменная создается внутри функции, которая хранится в статической памяти программ, а не в стеке.

  • Инициализация статической переменной будет выполнена при первом вызове функции.

  • Статическая переменная сохранит значение в нескольких вызовах функций

  • Время жизни статической переменной - Программа

enter image description here

Примеры

#include <iostream>

using namespace std;

class CVariableTesting 
{
    public:

    void FuncWithStaticVariable();
    void FuncWithAutoVariable();

};

void CVariableTesting::FuncWithStaticVariable()
{
    static int staticVar;
    cout<<"Variable Value : "<<staticVar<<endl;
    staticVar++;
}
void CVariableTesting::FuncWithAutoVariable()
{
    int autoVar = 0;
    cout<<"Variable Value : "<<autoVar<<endl;
    autoVar++;
}


int main()
{
    CVariableTesting objCVariableTesting;
    cout<<"Static Variable";
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();

    cout<<endl;
    cout<<"Auto Variable";
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();

    return 0;
}

Вывод:

Статическая переменная

Значение переменной: 0
Значение переменной: 1
Значение переменной: 2
Значение переменной: 3
Значение переменной: 4

Авто переменная

Значение переменной: 0
Значение переменной: 0
Значение переменной: 0
Значение переменной: 0
Значение переменной: 0

Ответ 4

Спасибо за хороший пример! Был бы способ фактически достичь чего-то, что делает область статического int я специфичной для экземпляра, так что, например, o1.foo();//i = 1 и $o2.foo();//i >= 1...? - Одевание

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

Ответ 5

Я однажды оставил const char *, который был статическим локальным (в функции-члене), указанным в другой строке стиля c, которая фактически была членом экземпляра класса. Деструктор объекта освободил память указателя экземпляра в этом конкретном случае, а следующий экземпляр класса имел значение нежелательной почты, поскольку среда выполнения считала статическую локалью инициализированной, даже если она оставила указатель там, где это не должно быть.

Статические локали проще всего использовать внутри глобальных функций или статических функций-членов.

Поведение шаблона было рассмотрено выше. Как насчет безопасности потоков (или, если я не ошибаюсь, их отсутствие)?

Ответ 6

Упрощенный ответ:

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