프로그래밍선임 C++ 개발자

C++에서 'One Definition Rule (ODR)' 문제에 대해 설명해주세요. 이 규칙이 대형 프로젝트에 어떻게 영향을 미치고 위반을 피하려면 어떻게 해야 합니까?

Hintsage AI 어시스턴트로 면접 통과

답변

**One Definition Rule (ODR)**는 C++의 근본적인 규칙으로, 프로그램 전체(모든 translation unit)에서 각 객체, 함수 또는 클래스에 대해 정확히 하나의 정의(implementation)가 있어야 한다는 요구 사항입니다.

ODR은 다음과 같은 경우에 위반됩니다:

  • 서로 다른 코드로 동일한 함수/클래스의 여러 구현이 서로 다른 .cpp 파일에 나타나는 경우.
  • 인라인 함수나 템플릿이 서로 다른 연결 지점에서 다른 구현을 가지는 경우.

이로 인해 잡기 힘든 예기치 않은 버그, 잘못된 링크 또는 더 심각하게는 프로그램의 동작이 컴파일 방법에 따라 달라지는 상황이 발생합니다.

왜 위반되는가:

대형 프로젝트에서는 종종 .h 파일을 버전 관리 없이 복사/수정 하거나, 코드를 여러 모듈로 분리하여 독립적으로 컴파일하는 경우가 많습니다. 누군가 인라인 함수를 한 곳만 변경하면 나머지 소스 파일은 오래된 버전을 가질 수 있습니다.

어떻게 피할 것인가:

  • 인라인이 아닌 클래스 바깥의 함수를 .h 파일에서 정의하지 마십시오.
  • 포함 가드를 사용하고 정의가 하나의 장소에만 존재하도록 관리하십시오.
  • 상수 변수에 대해 constexpr 또는 C++17에서 inline 변수를 사용하십시오.

속임수 질문

서로 다른 .cpp 파일에서 같은 이름과 서로 다른 구현을 가진 static 함수(static void foo())를 정의해도 문제가 없습니까?

많은 사람들은 static 함수가 모듈 간에 서로 영향을 미치지 않다고 생각합니다. 답은: 예, 가능합니다. 각 함수는 내부 링크(자신의 translation unit 내에서만 표시됨)를 가지므로 그렇습니다. 그러나 인라인 함수와 템플릿에 대해서는 이러한 보장이 되지 않으며, 이는 종종 혼동됩니다.

예제:

// file1.cpp static void foo() { std::cout << "A"; } // file2.cpp static void foo() { std::cout << "B"; }

이러한 모듈에서의 호출은 독립적입니다.

주제에 대한 세부사항을 몰라서 발생한 실제 오류 사례


이야기

대형 프로젝트에서 한 개발자가 .h 파일의 클론 중 하나에서만 인라인 함수의 본문을 변경했습니다. 빌드 후 일부 동작이 예측할 수 없게 되었고, 일부 모듈은 이전 알고리즘을 사용하고 다른 모듈은 새로운 알고리즘을 사용했습니다. 원인은 인라인 함수에 대한 ODR 위반이었습니다.



이야기

C++17로 마이그레이션할 때, 상수 변수가 여러 헤더 파일에서 inline 키워드 없이 정의되었습니다. 링크에서 중복 기호 오류가 다수 발생했습니다. 이를 수정하기 위해 'inline const'로 변수를 선언했습니다.



이야기

생성된 .h 파일에 동일한 템플릿 클래스의 메서드에 대한 두 개의 구현이 서로 다른 빌드에서 ifdef 검사로 구별되어 포함된 것이 늦게 발견되었습니다. 이후 애플리케이션이 관련 모듈 간 ABI 불일치로 인해 주기적으로 크래시되었습니다.