멤버 변수를 선언 된 순서대로 초기화해야하는 이유는 무엇입니까?
오늘 코드를 작성하다가 이상한 컴파일 오류가 발생했는데, 이는 선언 된 순서와 다른 순서로 멤버 변수를 초기화함으로써 발생하는 것 같습니다.
예:
class Test {
int a;
int b;
public:
Test() : b(1), a(2) {
}
};
int main() {
Test test;
return 0;
}
그런 다음 컴파일하면 다음과 -Werror -Wall
같습니다.
$ 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에게 경고를 넘겨달라고 명시 적으로 요구 하고 있다는 것을 알고 있지만, 그들 모두에 대한 이유가 있다고 가정합니다. 그렇다면 멤버 변수를 초기화하는 순서는 어떻게 중요할까요?
그 이유는 생성자에서 초기화 한 순서가 아니라 클래스에서 선언 된 순서대로 초기화되고 생성자의 순서가 사용되지 않는다는 경고를 표시하기 때문입니다.
이는 초기화가 b
의존적 a
이거나 그 반대의 경우 오류를 방지하는 데 도움이됩니다 .
이 순서를 지정하는 이유는 소멸자가 하나 뿐이고 클래스 멤버를 파괴하기 위해 "역순"을 선택해야하기 때문입니다. 이 경우 가장 간단한 해결책은 클래스 내에서 선언 순서를 사용하여 속성이 항상 올바른 역순으로 소멸되도록하는 것입니다.
멤버 변수를 선언 된 순서대로 초기화해야하는 이유는 무엇입니까?
멤버 는 원하든 원하지 않든 선언 된 순서대로 초기화됩니다. 경고는 요청한 순서가 실제 초기화 실행 순서와 다르다는 것을 알려줍니다.
가독성을 떨어 뜨리고 잠재적으로 오해의 소지가 있기 때문에 그렇게해서는 안됩니다.
그랬다면 :
Test() : b(1), a(b) {}
b
그러면 a
둘 다로 설정된 것처럼 1
보이지만 실제로 초기화되지 않은 값은 b
로 초기화 a
되기 전에 b
초기화하는 데 사용 됩니다 1
.
실제로 컴파일러 는 이니셜 라이저를 다른 순서로 작성하더라도 항상 선언 순서대로 변수를 초기화합니다. 따라서 선언 순서대로 초기화를 작성하지 않으면 초기화 순서가 초기화 순서와 맞지 않아 초기화가 서로 의존하는 경우 미묘한 버그가 발생할 수 있습니다.
예를 들어, 코드를 고려하십시오.
Test(): b(42), a(b) {}
는 a
이전 b
에 초기화 되었기 때문에 버그 이지만 괜찮아 보입니다 . 선언 순서 (초기화 순서)로 작성하면 버그가 분명해집니다.
Test(): a(b), b(42) {}
버그는 그보다 더 미묘 할 수도 있습니다. 예를 들어 생성자에서 무언가를 출력하는 클래스 유형을 상상 a
하고 b
있습니다. 그런 다음 "잘못된"순서를 사용하면 실제로 그 반대가 발생할 때 b
'의 출력이 a
' 보다 먼저 나타나야 한다고 생각할 것입니다 . 경우 a
첫 등장의 출력이 또한 버그 잘못된 파일로 이어질 것입니다,하지만 방법이없는 생성자가 재정렬이 경우, 또는 컴파일러가 알 수없는 떨어져 사실에서 다른 번역 단위 (에있는 경우 컴파일러는 문제가 나타날 수있다 버그가 아닙니다). 따라서 컴파일러가 일치하지 않는 순서의 모든 인스턴스에 대해 경고하는 것이 합리적입니다.
나는 -Wall이 GCC에게 경고를 넘겨달라고 명시 적으로 요청하고 있다는 것을 알고 있지만, 그 모두에 대한 이유가 있다고 생각합니다.
-벽은 시작에 불과합니다. 이름이 의미하는 것과 달리 -Wall은 모든 경고를 활성화하지 않습니다. "정상적인"경고가 몇 가지 있지만, 바로 -Wall이 활성화하지 않는 경고입니다. 나는 항상 -Wall과 다른 것을 사용합니다.
귀하의 불만에 대해서는 다른 사람들이 이미 언급했듯이이 경고에 대한 매우 좋은 이유가 있습니다. 순서를 지정했다고해서 컴파일러가 해당 순서를 사용한다는 의미는 아닙니다. 컴파일러가 표준에 따라 사용해야하는 순서는 클래스 정의를 기반으로합니다.
이니셜 라이저 목록은 임의의 순서로 변수를 초기화 할 수있는 유연성을 제공합니다. 그러나 실제 초기화는 클래스 멤버를 선언 한 순서에 따라 발생합니다. 이 경고를 피하려면 초기화 / 선언을 다시 정렬해야합니다.
'program tip' 카테고리의 다른 글
Java로 인증 된 HTTP 프록시 (0) | 2020.12.28 |
---|---|
WCF 4.0과 함께 Entity Framework 4.0을 사용하는 DataContractSerializer 오류 (0) | 2020.12.28 |
Java : 동기화 된 블록에서 wait () 잠금 해제 (0) | 2020.12.28 |
한 위치에서 다른 위치로 파일을 복사하는 방법은 무엇입니까? (0) | 2020.12.28 |
Java String 변수의 마지막 문자 제거 (0) | 2020.12.28 |