Programing

함수 수준 정적 변수는 언제 할당 / 초기화됩니까?

lottogame 2020. 10. 5. 07:28
반응형

함수 수준 정적 변수는 언제 할당 / 초기화됩니까?


저는 전역 적으로 선언 된 변수가 프로그램 시작 시간에 할당 (적용 가능한 경우 초기화)된다는 것을 확신합니다.

int globalgarbage;
unsigned int anumber = 42;

그러나 함수 내에 정의 된 정적 요소는 어떻습니까?

void doSomething()
{
  static bool globalish = true;
  // ...
}

공간은 언제 globalish할당됩니까? 프로그램이 언제 시작되는지 짐작하고 있습니다. 하지만 그때도 초기화됩니까? 아니면 doSomething()처음 호출 될 때 초기화 됩니까?


궁금해서 다음 테스트 프로그램을 작성하고 g ++ 버전 4.1.2로 컴파일했습니다.

include <iostream>
#include <string>

using namespace std;

class test
{
public:
        test(const char *name)
                : _name(name)
        {
                cout << _name << " created" << endl;
        }

        ~test()
        {
                cout << _name << " destroyed" << endl;
        }

        string _name;
};

test t("global variable");

void f()
{
        static test t("static variable");

        test t2("Local variable");

        cout << "Function executed" << endl;
}


int main()
{
        test t("local to main");

        cout << "Program start" << endl;

        f();

        cout << "Program end" << endl;
        return 0;
}

결과는 내가 기대했던 것과는 달랐다. 함수가 처음 호출 될 때까지 정적 개체의 생성자가 호출되지 않았습니다. 다음은 출력입니다.

global variable created
local to main created
Program start
static variable created
Local variable created
Function executed
Local variable destroyed
Program end
local to main destroyed
static variable destroyed
global variable destroyed

C ++ 표준의 관련 설명 :

3.6.2 로컬이 아닌 객체의 초기화 [basic.start.init]

1

정적 저장 기간 ( basic.stc.static )을 가진 객체의 저장은 다른 초기화가 발생하기 전에 0으로 초기화되어야합니다 ( dcl.init ). 정적 저장 기간이 상수 표현식 ( expr.const )으로 초기화 된 POD 유형 ( basic.types )의 객체는 동적 초기화가 발생하기 전에 초기화되어야합니다. 동일한 번역 단위에서 정의되고 동적으로 초기화 된 정적 저장 기간을 가진 네임 스페이스 범위의 개체는 해당 정의가 번역 단위에 나타나는 순서대로 초기화됩니다. [참고 : dcl.init.aggr 은 집계 멤버가 초기화되는 순서를 설명합니다. 로컬 정적 개체의 초기화는 stmt.dcl에 설명되어 있습니다.. ]

[컴파일러 작성자에게 더 많은 자유를 추가하는 아래 텍스트]

6.7 선언문 [stmt.dcl]

...

4

다른 초기화가 발생하기 전에 정적 저장 기간 ( basic.stc.static )이 있는 모든 로컬 객체 의 제로 초기화 ( dcl.init )가 수행됩니다. 상수 표현식으로 초기화 된 정적 저장 기간 이있는 POD 유형 ( basic.types ) 의 로컬 객체 는 블록이 처음 입력되기 전에 초기화됩니다. 구현은 네임 스페이스 범위 ( basic.start.init) 에서 정적 저장 기간을 사용하여 개체를 정적으로 초기화 할 수있는 것과 동일한 조건에서 정적 저장 기간이있는 다른 로컬 개체의 초기 초기화를 수행 할 수 있습니다.). 그렇지 않으면 이러한 개체는 처음 컨트롤이 선언을 통과 할 때 초기화됩니다. 이러한 객체는 초기화 완료시 초기화 된 것으로 간주됩니다. 예외를 throw하여 초기화가 종료되면 초기화가 완료되지 않았으므로 다음에 제어가 선언에 들어갈 때 다시 시도됩니다. 개체가 초기화되는 동안 컨트롤이 (재귀 적으로) 선언을 다시 입력하면 동작이 정의되지 않습니다. [ 예 :

      int foo(int i)
      {
          static int s = foo(2*i);  // recursive call - undefined
          return i+1;
      }

- 최종 예 ]

5

정적 저장 기간이있는 로컬 개체의 소멸자는 변수가 생성 된 경우에만 실행됩니다. [참고 : basic.start.term 은 정적 저장 기간이있는 로컬 개체가 삭제되는 순서를 설명합니다. ]


모든 정적 변수에 대한 메모리는 프로그램로드시 할당됩니다. 그러나 로컬 정적 변수는 프로그램 시작 시가 아니라 처음 사용될 때 생성되고 초기화됩니다. 그것에 대한 좋은 읽기와 일반적으로 정적이 여기에 있습니다 . 일반적으로 이러한 문제 중 일부는 구현에 의존한다고 생각합니다. 특히 메모리에서이 항목이 어디에 있는지 알고 싶은 경우에는 더욱 그렇습니다.


컴파일러는 foo프로그램로드시 함수 정의 된 정적 변수를 할당하지만 컴파일러는 함수 에 몇 가지 추가 명령 (기계 코드)을 추가 foo하여 처음 호출 될 때이 추가 코드가 정적 변수를 초기화합니다 ( 예 : 해당되는 경우 생성자 호출).

@Adam : 컴파일러에 의한 코드 주입이면에서 이것이 당신이 본 결과의 이유입니다.


Adam Pierce의 코드를 다시 테스트 하고 클래스의 정적 변수와 POD 유형의 두 가지 사례를 추가했습니다. 내 컴파일러는 Windows OS (MinGW-32)에서 g ++ 4.8.1입니다. 결과는 클래스의 정적 변수가 전역 변수와 동일하게 처리됩니다. 생성자는 주 함수에 들어가기 전에 호출됩니다.

  • 결론 (g ++, Windows 환경의 경우) :

    1. class : constructor의 전역 변수정적 멤버는 함수 (1)에 들어가기 전에 호출 됩니다.
    2. 로컬 정적 변수 : 생성자는 실행이 처음 선언에 도달 할 때만 호출됩니다.
    3. If Local static variable is POD type, then it is also initialized before enter main function (1). Example for POD type: static int number = 10;

(1): The correct state should be: "before any function from the same translation unit is called". However, for simple, as in example below, then it is main function.

include < iostream>

#include < string>

using namespace std;

class test
{
public:
   test(const char *name)
            : _name(name)
    {
            cout << _name << " created" << endl;
    }

    ~test()
    {
            cout << _name << " destroyed" << endl;
    }

    string _name;
    static test t; // static member
 };
test test::t("static in class");

test t("global variable");

void f()
{
    static  test t("static variable");
    static int num = 10 ; // POD type, init before enter main function

    test t2("Local variable");
    cout << "Function executed" << endl;
}

int main()
{
    test t("local to main");
    cout << "Program start" << endl;
    f();
    cout << "Program end" << endl;
    return 0;
 }

result:

static in class created
global variable created
local to main created
Program start
static variable created
Local variable created
Function executed
Local variable destroyed
Program end
local to main destroyed
static variable destroyed
global variable destroyed
static in class destroyed

Anybody tested in Linux env ?


Static variables are allocated inside a code segment -- they are part of the executable image, and so are mapped in already initialized.

Static variables within function scope are treated the same, the scoping is purely a language level construct.

For this reason you are guaranteed that a static variable will be initialized to 0 (unless you specify something else) rather than an undefined value.

There are some other facets to initialization you can take advantage off -- for example shared segments allow different instances of your executable running at once to access the same static variables.

In C++ (globally scoped) static objects have their constructors called as part of the program start up, under the control of the C runtime library. Under Visual C++ at least the order that objects are initialized in can be controlled by the init_seg pragma.


Or is it initialized when doSomething() is first called?

Yes, it is. This, among other things, lets you initialize globally-accessed data structures when it is appropriate, for example inside try/catch blocks. E.g. instead of

int foo = init(); // bad if init() throws something

int main() {
  try {
    ...
  }
  catch(...){
    ...
  }
}

you can write

int& foo() {
  static int myfoo = init();
  return myfoo;
}

and use it inside the try/catch block. On the first call, the variable will be initialized. Then, on the first and next calls, its value will be returned (by reference).

참고URL : https://stackoverflow.com/questions/55510/when-do-function-level-static-variables-get-allocated-initialized

반응형