15

이 프로그램 :전역 변수의 소멸자에서 thread_local 변수를 초기화하는 것이 합법적입니까?

#include <iostream> 

struct Foo { 
    Foo() { 
     std::cout << "Foo()\n"; 
    } 

    ~Foo() { 
     std::cout << "~Foo()\n"; 
    } 
}; 

struct Bar { 
    Bar() { 
     std::cout << "Bar()\n"; 
    } 

    ~Bar() { 
     std::cout << "~Bar()\n"; 
     thread_local Foo foo; 
    } 
}; 

Bar bar; 

int main() { 
    return 0; 
} 

인쇄 나에게

Bar() 
~Bar() 
Foo() 

(GCC 6.1, 리눅스, - 64). ~ Foo()는 호출되지 않습니다. 그것은 예상 된 행동입니까?

+0

합법적이든 아니든, 왜 그럴 수 있습니까? –

+3

@DavidHaim 나는'libC++ abi' ('__cxa_thread_atexit()'의 일부를 구현하려고 시도하고 있는데,이 경우를 처리해야하는지 아닌지 궁금합니다. –

+5

아마도'foo' 전에'cout'이 파괴 될 것입니다. 'Foo'의 소멸자로부터 예외를 던져보고'std :: terminate'가 호출되는지보십시오. –

답변

9

표준은이 경우를 다루지 않습니다. 가장 엄격한 지침은 정적 저장 기간을 가진 객체의 소멸자에서 thread_local을 초기화하는 것이 합법적이지만 프로그램이 정상적으로 완료되도록 허용하는 것은 불법입니다.

문제 [basic.start.term] 생긴다 :

1 - 초기화 된 개체 소멸자 ([class.dtor]) 정적 저장 지속 시간 (즉, 그 수명 ([basic.life]가) 시작 개체) main에서 리턴하고 std :: exit ([support.start.term])를 호출 한 결과로 호출됩니다. 지정된 thread 내의 thread 스토리지 존속 기간을 가지는 초기화 된 오브젝트의 소멸자는, 그 thread의 초기 함수로부터 돌아 왔을 때, 및 그 thread가 std :: exit를 호출 한 결과로서 불려갑니다. 스레드 내에서 스레드 저장 기간을 가진 초기화 된 모든 객체에 대한 소멸자의 완료는 정적 저장 기간이있는 객체의 소멸자가 시작되기 전에 순서가 지정됩니다. [...]

그래서 bar::~Bar::foo::~Foo 완료 모순이다 bar::~Bar 개시 전 서열화된다.

유일한 얻을 아웃 [basic.start.term]/1 만 그의 일생 프로그램/스레드 종료의 시점에서 시작 개체에 적용한다고 주장 할 수 있지만, 콘트라 [stmt.dcl]가 있습니다

5 - 정적 또는 스레드 저장 기간이있는 블록 범위 개체의 소멸자는 생성 된 경우에만 실행됩니다. [참고 : [basic.start.term]은 정적 및 스레드 저장 기간이있는 블록 범위 객체가 삭제되는 순서를 설명합니다. - 끝 노트]

이것은 정상적인 스레드 및 프로그램 종료, 메인에서의 반환 또는 스레드 함수 또는 std::exit을 호출하는 경우에만 적용됩니다.

또한 [basic.stc.thread]가 가지고

스레드 저장 기간의 변수는 제 ODR 사용 전에 초기화한다 구성된 경우 ([basic.def.odr])과, 쓰레드 종료시 파기 .

여기서 "shall"은 사용자가 아니라 구현자를위한 지침입니다.

[basic.start.term]/2가 적용되지 않기 때문에 (이전에 파괴되지 않았 음) 소멸자 범위가 시작된 thread_local의 수명 시작에는 아무런 문제가 없음에 유의하십시오. 그래서 프로그램을 정상적으로 완료 할 때 정의되지 않은 동작이 발생한다고 생각합니다.

비슷한 질문이 이전에 제기되었지만, 정적 대 정적 저장 기간은 thread_local 대 정적이 아닙니다. Destruction of objects with static storage duration (및 https://groups.google.com/forum/#!topic/comp.std.c++/Tunyu2IJ6w0) 및 Destructor of a static object constructed within the destructor of another static object. 후자의 질문에 James Kanze와 동의하는 경향이 있습니다. 표준에서는 정의하지 않기 때문에이 동작은 정의되지 않습니다. [defns.undefined]이 여기에 해당됩니다. 가장 좋은 방법은 결함 보고서를 열어 놓은 사람 (staticthread_local의 소멸자에서 초기화 된 staticthread_local의 모든 조합 포함)을 열어 확실한 답을 얻기를 바랍니다.

+0

저에게 감사드립니다! –