2012-08-31 1 views
43

오늘 코드를 작성하고 이상한 컴파일 오류가 발생했습니다.이 오류는 선언 된 순서와 다른 순서로 멤버 변수를 초기화하여 발생하는 것으로 보입니다.멤버 변수가 선언 된 순서대로 초기화해야하는 이유는 무엇입니까?

예 : -Werror -Wall와 그 다음 내가 그것을 컴파일하는 경우

class Test { 
    int a; 
    int b; 

public: 
    Test() : b(1), a(2) { 
    } 
}; 

int main() { 
    Test test; 
    return 0; 
} 

:

$ g++ -Werror -Wall test.cpp 
test.cpp: In constructor ‘Test::Test()’: 
test.cpp:3:9: error: ‘Test::b’ will be initialized after [-Werror=reorder] 
test.cpp:2:9: error: ‘int Test::a’ [-Werror=reorder] 
test.cpp:6:5: error: when initialized here [-Werror=reorder] 
cc1plus: all warnings being treated as errors 

내가 -Wall 명시 적으로 이상 - 더 - 상단 경고와 함께 갈 GCC를 요구하고 실현,하지만 난 거기에 가정 그들 모두를위한 이유. 그렇다면 멤버 변수를 초기화하는 순서가 어떻게 중요할까요?

+2

-Werror는 메시지에서 알 수 있듯이 모든 경고를 오류로 처리하도록 컴파일러에 지시합니다. 작성된 코드는 유효하며 그 의미는 잘 정의되어 있습니다 (그런 식으로 쓰지 않는 합리적인 인수가 있지만).하지만 -Werror를 사용하면 컴파일러가 올바른 코드를 컴파일하기를 거부하기 때문에 표준을 따르지 않습니다. –

답변

71

이유는 생성자에서 초기화 한 순서가 아니라 클래스에서 선언 된 순서로 초기화되기 때문입니다. 생성자의 순서가 사용되지 않을 것이라고 경고합니다.

b의 초기화가 a에 있거나 그 반대 인 경우 오류를 방지하는 데 도움이됩니다.

이 순서는 이유는 소멸자가 하나뿐이기 때문에 클래스 멤버를 파괴하기 위해 "역순"을 선택해야하기 때문입니다. 이 경우 가장 간단한 해결책은 속성이 항상 올바른 역순으로 파괴되었는지 확인하기 위해 클래스 내에서 선언 순서를 사용하는 것이 었습니다.

27

가독성을 떨어 뜨리고 오해의 소지가 있기 때문에 그렇게해서는 안됩니다.

당신이 한 경우

Test() : b(1), a(b) {} 

실제로 b의 초기화되지 않은 값이 b1에 초기화되기 전에 a을 초기화하는 데 사용되는 반면 b 다음 a가 모두 1로 설정 한 것으로 생각된다.

+2

+1은 예를 들어 순서가 실제로 중요한 이유와 누군가가 순서를 가정 할 경우 생성자에서 선언 한 내용을 보여줄 수있는 이유를 보여줍니다. – atuljangra

12

실제로 컴파일러 은 초기화 순서를 다른 순서로 쓰더라도 선언 순서대로 변수를 초기화합니다. 따라서 선언 순서대로 초기화를 작성하지 않으면 초기화 프로그램의 순서가 초기화 순서에 맞지 않으므로 초기화가 서로 의존하면 미묘한 버그가 발생할 수 있습니다. 예를 들어

는이 ab 전에 초기화되기 때문에 버그 코드

Test(): b(42), a(b) {} 

을 고려하지만, 확인 보인다. 당신이 (초기화의 순서입니다) 선언의 순서를 작성하는 경우, 버그는 분명 가져옵니다 버그는보다 미묘한 될 수 있음을

Test(): a(b), b(42) {} 

참고; 예를 들어, ab은 생성자에서 무언가를 출력하는 클래스 유형입니다. "부정확 한"순서를 사용하면 실제로는 그 반대가 일어날 때 b의 출력이 a 앞에 나타날 것이라고 생각할 것입니다. a의 출력이 처음 나타나는 경우 잘못된 파일로 이어질 수도 있습니다. 또한 버그이기도하지만 컴파일러가 다른 번역 단위에있는 경우 컴파일러에서 문제를 확인할 수있는 방법이 없습니다 (컴파일러가 순서 재 지정 여부를 알 수 있음을 제외하고는). 또는 버그가 아님). 따라서 컴파일러가 일치하지 않는 순서의 모든 인스턴스에 대해 경고하는 것이 합리적입니다.

36

멤버 변수가 선언 된 순서대로 초기화해야하는 이유는 무엇입니까?

당신이 원하는 여부 그들은, 선언 같은 순서로 초기화됩니다 회원. 경고는 요청한 순서가 실제 초기화 실행 순서와 다르다는 것을 알려줍니다.

+3

+1은 "compiler"라는 단어를 사용하지 않는 간결하고 정확한 답변입니다. –

+1

좋은 답변입니다. 이것이 모든 생성자가 결정 론적으로 컴파일되도록 만드는 C++ 표준이라고 가정하거나 멤버가 선언 된 순서대로 항상 초기화되어야하는 기술적/성능상의 이유가 있습니까? –

+4

@XavierHolt : 언어에서는 동적으로 할당 된 모든 객체에 대해 생성 및 파기의 순서가 바뀝니다. 초기화 순서가 이니셜 라이저 목록에 의해 결정된 경우, 다중 생성자가있는 클래스의 초기화 순서가 정의되지 않고 구성원의 삭제 순서도 정의되지 않습니다. 건설/파괴의 순서가 반대되는 이유는 대상이 다른 대상에 의존하는 경우 두 번째 대상이 첫 번째 대상보다 먼저 파괴되지 않도록하기 위해서입니다. –

5

나는 WCC가 GCC에 경고 메시지를 표시하도록 명시 적으로 요구하고 있지만, 나는 그 모두에 대한 이유가 있다고 가정한다.

- 단지 시작일뿐입니다. 이름에서 알 수있는 것과는 반대로 - 벽은 모든 경고를 활성화하지 않습니다. 틀림없이 "맨 위에"있는 몇 가지 경고가 있지만 그 경고는 벽이 작동하지 않는 것입니다. 나는 항상 벽과 플러스를 사용한다.

귀하의 불만 사항에 대해서는 다른 사람들이 이미 언급했듯이이 경고가 필요한 이유가 있습니다. 순서를 지정한다고해서 컴파일러가 해당 순서를 사용한다는 의미는 아닙니다. 컴파일러가 표준별로 사용해야하는 순서는 클래스 정의를 기반으로합니다.