C ++ 정적 const 변수 및 파괴
-
06-07-2019 - |
문제
간단한 C ++ 클래스로 이상한 행동을 만났습니다.
classa.h
class A
{
public:
A();
~A();
static const std::string CONST_STR;
};
classa.cpp
#include "classA.h"
#include <cassert>
const std::string A::CONST_STR("some text");
A::A()
{
assert(!CONST_STR.empty()); //OK
}
A::~A()
{
assert(!CONST_STR.empty()); //fails
}
main.cpp
#include <memory>
#include <classA.h>
std::auto_ptr<A> g_aStuff;
int main()
{
//do something ...
g_aStuff = std::auto_ptr<A>(new A());
//do something ...
return 0;
}
액세스 위반이나 비슷한 것을 기대하지만 정적 Const 문자열의 내용이 변경 될 수있을 것으로 기대하지 않습니다. 여기에 누구든지 그 코드에서 어떤 일이 일어나는지 좋은 설명이 있습니까?
고마워, 노버트
해결책
액세스 위반이나 비슷한 것을 기대하지만 정적 Const 문자열의 내용이 변경 될 수있을 것으로 기대하지 않습니다.
정의되지 않은 행동 : 정의되지 않았습니다. const_str가 파괴 된 경우 액세스하면 하드웨어 예외가 보장되지 않습니다. 충돌이 발생할 수 있지만 다시 주소는 빈 문자열처럼 보이는 데이터가 포함될 수 있습니다. 소멸자는 포인터 나 그 밖의 다른 것을 제거 할 수 있습니다.
이 경우 A 인스턴스가 Main ()에 할당 된 글로벌 스마트 포인터에도 저장되어 있다고 말합니다. 따라서 Const_str는 A 생성자에 액세스 할 때 구성되었지만 스마트 포인터가 파괴되기 전에 상당히 파괴 될 수 있습니다. 우리는 확실히 말할 수있는 전체 프로그램이 필요합니다.
편집 : 당신은 그렇게했습니다. const_str 및 g_astuff는 다른 컴파일 단위로 정의되므로 상대적인 구성 순서는 표준에 의해 정의되지 않습니다. Const_str가 먼저 파괴되고 있다고 생각합니다.
다른 팁
편집하다: 분명히 누락 된 A::
코드의 원래 게시물에서 오타였습니다.
원래 답변 :
당신은 가지고 있다는 것을 의미합니까?
const std::string ㅏ::CONST_STR("some text");
const_str가 클래스의 일부가되도록합니다 A
?
그렇지 않으면 당신은 그것을 별도로 선언하고 있습니다 ~ 아니다 정적 멤버를 초기화합니다 A
.
두 개의 다른 컴파일 단위로 2 개의 정적 변수를 만들고 있습니다. 어떤 순서가 초기화되는지 알 수있는 방법이 없습니다. 그러나 그들의 소멸자는 항상 역순으로 호출됩니다.
귀하의 경우 다음 시나리오가 발생한 것으로 보입니다.
g_aStuff constructor
CONST_STR constructor
main funciton initializes g_aStuff
CONST_str destructor
g_aStuff descrutor
이 시점에서 const_str.empty ()의 결과는 정의되지 않았습니다. 주장을 유발할 수 있습니다.
그만큼
const std::string CONST_STR("some text");
classa.cpp에 정의 된 A의 구성원이 아닙니다. 그 정의는 다음과 같습니다.
const std::string A::CONST_STR("some text");
표준은 다른 번역 단위로 글로벌/정적 개체의 초기화 순서를 지정하지 않습니다. 그러나 해당 번역 장치의 기능이 실행되기 전에 각 객체가 초기화 될 것을 보장합니다.
귀하의 경우에는 발생합니다 CONST_STR
이후에 초기화됩니다 g_aStuff
그리고 파괴의 순서는 건축 순서에서 역전되기 때문에 그 전에 파괴됩니다. 따라서 액세스 CONST_STR
~에서 A
의 파괴자는 정의되지 않은 행동을 호출합니다. 액세스 위반을받을 수도 있고 그렇지 않을 수도 있습니다.
CONST_STR
그러나 이전에 초기화되었습니다 A
의 생성자는 동일한 번역 장치에 있기 때문에 실행됩니다.
A (또는 A 형의 정적 클래스 멤버)가있는 경우 발생할 수 있습니다. 글로벌 및 정적의 초기화 순서는 정의되지 않기 때문에 (교차 번역 단위) 될 수 있습니다.
전체 코드를 살펴보면 편집 장치 (Classa.cpp 및 main.cpp)의 파괴 순서에 의존합니다. Main의 로컬로서 g_astuff를 만들면 ASSERS가 통과해야합니다.