[c++] C ++ 함수에서 정적 변수의 수명은 얼마입니까?

변수가 static함수 범위에서 선언 된 경우 한 번만 초기화되고 함수 호출간에 값이 유지됩니다. 수명이 정확히 무엇입니까? 생성자와 소멸자는 언제 호출됩니까?

void foo()
{
    static string plonk = "When will I die?";
}



답변

함수 static변수 의 수명은 프로그램 흐름 이 처음으로 선언을 만나고 프로그램 종료시 종료됩니다 [0]에 시작합니다 . 즉, 런타임은 실제로 구성된 경우에만 소장을 유지하기 위해 일부 장부 보관을 수행해야합니다.

표준 정적 객체의 소멸자가 완공의 역순으로 실행해야한다는 것을 말한다 있기 때문에 또한, [1] , 건설의 순서가 특정 프로그램의 실행에 따라 달라질 수 있습니다 건설의 순서가 고려되어야한다 .

struct emitter {
    string str;
    emitter(const string& s) : str(s) { cout << "Created " << str << endl; }
    ~emitter() { cout << "Destroyed " << str << endl; }
};

void foo(bool skip_first)
{
    if (!skip_first)
        static emitter a("in if");
    static emitter b("in foo");
}

int main(int argc, char*[])
{
    foo(argc != 2);
    if (argc == 3)
        foo(false);
}

산출:

C :> sample.exe
가 foo
에서 생성됨 foo에서 삭제됨

C :> sample.exe 1
foo로 작성된
경우에
생성됨 foo
에서
파기 된 경우

C :> SAMPLE.EXE 1 2
foo는에서 만든
경우에 만든
경우에 파괴
foo는 파괴

[0]이후 C ++ 98 [2] 이 멀티 스레드 환경 행동 얼마나 다수의 스레드에 대한 참조가없는 것은 불특정하고, 같은 문제가 될 수 로디를 언급한다.

[1] C ++ 98 섹션 3.6.3.1 [basic.start.term]

[2]C ++ 11에서 스태틱은 스레드 안전 방식으로 초기화되며 Magic Statics 라고도 합니다.


답변

Motti는 명령에 대해 옳지 만 고려해야 할 다른 사항이 있습니다.

컴파일러는 일반적으로 숨겨진 플래그 변수를 사용하여 로컬 정적이 이미 초기화되었는지 여부를 나타내며이 플래그는 함수의 모든 항목에서 확인됩니다. 분명히 이것은 약간의 성능 저하이지만, 더 중요한 것은이 플래그가 스레드로부터 안전하다는 보장이 없다는 것입니다.

위와 같이 로컬 정적이 있고 foo여러 스레드에서 호출 된 경우 경쟁 조건이 plonk잘못되거나 여러 번 초기화 될 수 있습니다. 또한이 경우 plonk구성한 스레드와 다른 스레드에 의해 파괴 될 수 있습니다.

표준이 말한 것에도 불구하고, 나는 로컬 정적 파괴의 실제 순서에 매우주의를 기울였습니다. 왜냐하면 정적이 파괴 된 후에도 여전히 유효한 정적에 의지 할 수 있기 때문에 추적하기가 실제로 어렵습니다.


답변

기존 설명은 6.7에서 발견 된 표준의 실제 규칙이 없으면 실제로 완전하지 않습니다.

정적 스토리지 기간 또는 스레드 스토리지 기간으로 모든 블록 범위 변수를 0으로 초기화하면 다른 초기화가 수행됩니다. 적용 가능한 경우 정적 스토리지 기간으로 블록 범위 엔티티의 지속적인 초기화는 블록이 처음 입력되기 전에 수행됩니다. 구현시 네임 스페이스 범위에서 정적 또는 스레드 스토리지 기간으로 변수를 정적으로 초기화 할 수있는 것과 동일한 조건에서 정적 또는 스레드 스토리지 기간으로 다른 블록 범위 변수의 초기 초기화를 수행 할 수 있습니다. 그렇지 않으면 이러한 변수는 제어가 선언을 처음 통과 할 때 초기화됩니다. 이러한 변수는 초기화가 완료되면 초기화 된 것으로 간주됩니다. 예외가 발생하여 초기화가 종료되면 초기화가 완료되지 않았으므로 다음에 컨트롤이 선언에 들어갈 때 다시 시도됩니다. 변수가 초기화되는 동안 제어가 동시에 선언에 들어가면 동시 실행은 초기화가 완료 될 때까지 기다려야합니다. 변수가 초기화되는 동안 제어가 선언을 재귀 적으로 다시 입력하면 동작이 정의되지 않습니다.


답변

FWIW, Codegear C ++ Builder는 표준에 따라 예상 순서대로 소멸되지 않습니다.

C:\> sample.exe 1 2
Created in foo
Created in if
Destroyed in foo
Destroyed in if

… 파괴 명령에 의존하지 않는 또 다른 이유입니다!


답변

정적 변수는 한 번 활동하기 시작하는 프로그램 실행 시작 과 프로그램 실행 종료까지 계속 사용할 수 있습니다.

정적 변수는 메모리데이터 세그먼트 에서 생성됩니다 .


답변