2013-01-11 3 views
8

내가 다음 코드에서 소멸자 몇 가지 문제를 가지고의 소멸자 내에서 건설 :소멸자는 다른 정적 객체

에서는 foo2에 대한 소멸자 bionic을 요구하고 glibc 위해이었다되지 않은 이유를
#include <stdlib.h> 
#include <cstdio> 

class Foo2 
{ 
    public: 
     Foo2() { printf("foo2 const\n"); } 

     ~Foo2() 
     { 
      printf("foo2 dest\n"); // <--- wasn't called for bionic libc 
     } 
}; 

static Foo2& GetFoo2() 
{ 
    static Foo2 foo2; 
    printf ("return foo2\n"); 
    return foo2; 
} 

class Foo1 
{ 
    public: 
     Foo1() { printf("foo1 const\n"); } 

     ~Foo1() 
     { 
      printf("foo1 dest\n"); 
      GetFoo2(); 
     } 
}; 

int main(int argc, const char* argv[]) 
{ 
     printf("main 1 \n"); 
     static Foo1 anotherFoo; 
     printf("main 2 \n"); 
} 

? 생체 공학에 대한

편집
출력 :

main 1 
foo1 const 
main 2 
foo1 dest 
foo2 const 
return foo2 

디버그 정보 : 나는 정적이 코드에서 볼

(gdb) break 22 
Breakpoint 1 at 0x8048858: file test.C, line 22. 
(gdb) info breakpoints 
Num  Type   Disp Enb Address What 
1  breakpoint  keep y 0x08048858 in Foo2::~Foo2() at test.C:22 
(gdb) cont 
[ exited with code 0] 
+3

출력을 표시합니다. –

+0

생체 공학 및 glibc 란 무엇입니까? –

+3

@LuchianGrigore 인기있는 두 가지 표준 C 및 C++ 라이브러리 구현 : glibc는 GNU이고, Bionic은 Android 용입니다. –

답변

6

표준 이 실제로 명확하지 않거나 ( 표준에서 찾을 수 없음) 코드에 정의되지 않은 동작이 있다고 생각합니다. 코드는 정적 객체의 소멸자 에 새 정적 객체를 생성합니다. 이 표준은 에게이 사건을 해결하지만,하지 않습니다 : 그것은 소멸자 건설의 반대 순서로 호출해야 함을 말하고 있는가

  1. . 귀하의 경우 이것은 건설되기 전에 GetFoo2의 정적 객체가 파괴되어야 함을 암시합니다. 이것은 자기 모순입니다.

  2. §3.6/3의 텍스트는 소멸자 의 순서를 설명하고 atexit으로 등록 된 기능을 설명합니다. 요구 사항은 각각 동일한 등록 메커니즘을 사용해야하는 입니다. exit (또는 main에서 반환 됨)을 호출하면 atexit을 호출하는 것은 정의되지 않은 동작입니다.

  3. 라고하는, 또한 §3.6/2있다 "그 함수 포함되어있는 경우 객체의 파괴 동안 파괴되었고 함수가 호출 정적 또는 스레드 저장 기간 의 블록 범위 객체 정적 또는 스레드 저장 기간 동안, 제어는 제어의 흐름이 이전에 파괴 된 블록 스코프 객체의 정의를 통과하면 정의되지 않은 동작을합니다. " 이 문장은 악의적 인 메시지 인 에 대해 이야기하지만, "아직 생성되지 않은"객체의 부재는 단지 감독 일 뿐이라고 생각하는 데는 많은 상상력을 얻지 못합니다. 결국

, 내 첫 번째 점은 위의 의도 관련하여 결정적인이라고 말할 것입니다. 이 국제 표준이 행동의 명시 적 정의를 생략하거나 프로그램이 잘못된 구조를 사용하거나 잘못된 데이터를 사용하는 경우 정의되지 않은 동작이 발생할 수 있습니다 (구체적으로는 이지만 의도는 나타냅니다). . " 이 경우에는 필수 동작에 대한 설명 만 불가능합니다. 구성하기 전에 개체를 파괴 할 수 없으므로 표준에서이 문제를 해결하는 방법에 대해서는 아무 것도 표시되지 않습니다 ( ).

+0

나는 덜 확신합니다.(1) 모든 정적이 스택 상에있는 것처럼,이 코드에 문제가있는 것처럼 생각합니다. (2) 정적 소멸자가 atexit을 사용한다고 생각하지 않습니다. 나는 이것이 잘 정의 된 행동이라고 생각한다. –

+0

§1.3.24에 기초한 undefined에 동의 할 수 있습니다. 나는 특정 사건을 다루는 §3.6 [해고]에서 아무것도 본 것이 없다 (n3337에서). 완전하게 처리되는 것은 객체가 다른 객체 다음에 생성되면 소멸자가 먼저 호출되지만 소멸자가 실행되는 동안 객체를 일상적으로 생성한다는 것입니다. –

+0

정의되지 않은 동작이나 모순이 보이지 않습니다. Foo1의 수명은 소멸자 호출이 시작된 이후 종료되었으므로 Foo2의 소멸자가 실행되어야하며 Foo1의 소멸자가 실행되어야합니다. –

5

모든 인스턴스.

결과적으로 소멸자는 main이 완료된 후에 실행 파일의 끝에서 호출됩니다.

소멸자가 호출되지 않았 으면 버그였습니다.

+3

'foo2'처럼 보이는 것이 프로그램이 종료 될 때까지는 생성되지 않을 것입니다. anotherFoo'가 파괴되었습니다. – JasonD

+0

내가 본 인스턴스는'main()'보다 먼저 구성되어서는 안됩니다. 그것들은 모두 지역적 특성을 지니고 있으며 처음으로 범위에 포함되어야합니다. –

+0

당신은 나를 의심스럽게 생각합니다. 저는 정적 인스턴스의 생성에 대해서 점검 할 것입니다. –

4

정적 개체는 프로그램이 존재할 때 파괴됩니다. ~Foo2()에 중단 점을두면 진단에 도움이되는 파일이 표시되거나 로그를 작성합니다. 실제로 호출되지 않으면 컴파일러 버그입니다.

enter image description here

그리고 질문에 대답하기 위해 그림을 업로드 할 재미 있어요.

+0

재미 있지만, 컴파일러가 동의하지 않으면 대답은 자신의 주장을 뒷받침하는 상위 기관 (표준)을 참조해야합니다. –

+0

또한 로그 사용에 관해서는 이미 로그로 stdout을 사용하고 있습니다! –

+0

@MooingDuck 그는 내 게시물 후 영업 갱신 : – billz

4

C++ 11 3.6.3/1 : 소멸자 정적 저장 기간이 초기화 된 오브젝트 [...]의 시점에서 main

에서 복귀의 결과로서 호출되는 상기 프로그램은 main, anotherFoo에서 초기화되었습니다. 하지만 foo2anotherFoo을 삭제하는 동안 GetFoo2에 처음 호출 할 때까지 초기화되지 않았기 때문에 초기화되지 않았습니다. 따라서 규칙을 엄격하게 해석하면 소멸자를 호출하면 안됩니다.

+0

또는 생성자 전에 소멸자를 호출해야합니다. 또는 무엇이든. 나는 그것이 정의되지 않은 행동의 경우라고 생각한다. –

+0

@JamesKanze : 생성자보다 먼저 소멸자를 호출해야한다는 것을 의미하지는 않습니다. "초기화 된 객체 **에 대한 소멸자 ** [...]"라고합니다. –

+0

그리고 프로그램을 나가기 전에 개체가 초기화됩니다. (그러나 나는 표준이 요구되는 행동에 대해 명확하지 않다는 것에 동의한다. 그래서 나는 그것이 정의되지 않은 행동이라고 주장 할 것이다.) –