멤버 함수의 정적 변수


158

누군가 C ++에서 멤버 함수의 정적 변수가 어떻게 작동하는지 설명 할 수 있습니까?

다음과 같은 클래스가 주어집니다.

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

의 여러 인스턴스를 선언하면 한 인스턴스를 A호출 foo()하면 i모든 인스턴스 에서 정적 변수가 증가 합니까? 아니면 그 중 하나만 호출 되었습니까?

각 인스턴스에는 자체 사본이 있다고 가정 i했지만 다른 코드를 단계별로 실행하면 다르게 표시됩니다.

답변:


169

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

3
좋은 예를 주셔서 감사합니다! 이 사실의 범위를 만드는 것을 달성 할 수있는 방법이 될 것입니다 static int i, 인스턴스에 특정을 그 예를 들어 그렇게 o1.foo(); // i = 1하고 $o2.foo(); // i = 1...?
Stingery

14
이것이 당신이 찾고있는 스타일이 아닐 수도 있지만, 클래스 A의 개인 데이터 멤버를 만드는 것은 설명하는 효과가 있습니다. 이름 충돌이 우려되는 경우 m_i의 상태를 나타내는 등의 접 두부를 추가 할 수 있습니다 .
Carl Morris

137

static불행히도 키워드 는 C ++에서 관련이없는 몇 가지 의미가 있습니다.

  1. 데이터 멤버에 사용되는 경우 데이터가 인스턴스가 아니라 클래스에 할당 됨을 의미 합니다.

  2. 함수 내부의 데이터에 사용되는 경우 데이터가 정적으로 할당 되고 블록을 처음 입력 할 때 초기화 되고 프로그램이 종료 될 때까지 지속됨을 의미합니다. 또한 변수는 함수 내에서만 볼 수 있습니다. 로컬 스태틱의이 특별한 기능은 종종 싱글 톤의 게으른 구성을 구현하는 데 사용됩니다.

  3. 컴파일 단위 레벨 (모듈)에서 사용될 때 변수는 전역 변수와 유사하지만 (즉, 종료 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;
}

41
+1 keyword static unfortunately has a few different unrelated meanings in C++: +
iammilind

감사합니다
Erin

템플릿을 사용한 트릭이 마음에 듭니다. 나는 그것을 사용할 변명을 기다릴 수 없다.
토마스 Zato - 분석 재개 모니카

"이름없는 네임 스페이스를 선호하는 것이 다소 낙담했다"는 사람이 있습니까?
austinmarton

3
@austinmarton : " 'local to translation unit'을 나타 내기 위해 static을 사용하는 것은 C ++에서 더 이상 사용되지 않습니다. 대신 이름없는 네임 스페이스를 사용하십시오 (8.2.5.1)"(내 판의 C ++ Programming Language) (1999 년 9 월 10 일자)에 있습니다. at 819 페이지.
6502

2

함수 내부의 정적 변수

  • 정적 변수는 함수 내부에 생성되며 스택이 아닌 프로그램의 정적 메모리에 저장됩니다.

  • 정적 변수 초기화는 함수의 첫 번째 호출에서 수행됩니다.

  • 정적 변수는 여러 함수 호출에서 값을 유지합니다

  • 정적 변수의 수명은 프로그램입니다

여기에 이미지 설명을 입력하십시오

#include <iostream>

using namespace std;

class CVariableTesting 
{
    public:
    
    void FuncWithStaticVariable();
    void FuncWithAutoVariable();

};

void CVariableTesting::FuncWithStaticVariable()
{
    static int staticVar = 0; //staticVar is initialised by 0 the first time
    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


-2

간단한 답변 :

정적 변수는 (템플릿 class되지 않은) 함수 또는 (템플릿되지 않은) 함수의 멤버인지 여부에 관계없이 기술적으로는 범위가 class또는 기능으로 제한되는 전역 레이블처럼 동작 합니다.


9
아닙니다. 전역은 프로그램 시작시 초기화되고 함수 정적은 처음 사용할 때 초기화됩니다. 이것은 차이입니다.
6502

나는 이것이 일어날 것이라고 생각하지 않습니다. 그러나 이것은 어쨌든 컴파일러 고유해야합니다.
0xbadf00d 2016 년

2
그렇다면 C ++ 표준의 3.6.1은 시작시 정적 저장 시간을 사용하여 네임 스페이스 범위의 개체를 생성하도록 지시합니다. 6.7 (4)는 일반적으로 "... 제어가 선언을 처음 통과 할 때 그러한 변수가 초기화된다; 그러한 변수는 초기화가 완료되면 초기화 된 것으로 간주된다"고 규정하고있다. 그런데 처음 사용시 초기화는 게으른 싱글 톤 구성을 구현하는 데 매우 편리합니다.
6502

3.7.4 : "해당되는 경우 정적 저장 기간을 갖는 블록 범위 엔티티의 상수 초기화 (3.6.2)는 블록이 처음 입력되기 전에 수행됩니다. 구현시 다른 블록 범위 변수의 초기 초기화를 수행 할 수 있습니다. 네임 스페이스 범위 (3.6.2)에서 정적 또는 스레드 스토리지 기간으로 변수를 정적으로 초기화 할 수있는 것과 동일한 조건에서 정적 또는 스레드 스토리지 기간. 그렇지 않으면 이러한 변수는 제어가 선언을 처음 통과 할 때 초기화됩니다. "
0xbadf00d

1
그러나 흥미롭게도 : 1) 상수 초기화의 경우 블록에 처음 들어가기 전에 로컬 정적을 초기화 할 수 있는지 여부는 관련이 없습니다 (변수는 블록 내부에서만 볼 수 있으며 상수 초기화는 부작용이 없습니다). 2) 게시물의 지속적인 초기화에 대해서는 언급되지 않았습니다. 3) 로컬 정적은 상수가 아닌 초기화와 같이 매우 유용합니다. MyClass& instance(){ static MyClass x("config.ini"); return x; }단일 스레드 사용을위한 유효한 이식 가능한 구현은 로컬 정적이 말에도 불구하고 단순히 전역과 같지 않기 때문에 정확합니다.
6502
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.