단일 정의 규칙

One Definition Rule

One Definition Rule(ODR; 단일 정의 규칙)은 C++ 프로그래밍 언어의 중요한 규칙이며 오브젝트 및 비인라인 함수는 프로그램 전체와 템플릿 및 유형에서 여러 개의 정의를 변환 단위로 지정할 수 없습니다.ISO C++ 표준(ISO/IEC 14882) 2003 섹션 3.2에 정의되어 있습니다.

요약

즉, ODR에는 다음과 같이 기술되어 있습니다.

  1. 모든 변환 단위에서 템플릿, 유형, 함수 또는 개체에는 여러 정의를 사용할 수 없습니다.이들 중 일부는 임의의 수의 선언을 가질 수 있습니다.정의는 인스턴스를 제공합니다.
  2. 전체 프로그램에서 개체 또는 비인라인 함수는 둘 이상의 정의를 가질 수 없습니다. 개체 또는 함수가 사용되는 경우 해당 함수는 정확히 하나의 정의를 가져야 합니다.사용되지 않는 개체 또는 함수를 선언할 수 있습니다. 이 경우 정의를 제공할 필요가 없습니다.어떤 경우에도 두 개 이상의 정의는 있을 수 없습니다.
  3. 유형, 템플릿 및 외부 인라인 함수 등의 일부 항목을 여러 변환 단위로 정의할 수 있습니다.지정된 엔티티에 대해 각 정의의 토큰 시퀀스는 동일해야 합니다.다른 변환 단위의 외부 오브젝트 및 함수는 이름과 유형이 동일하더라도 서로 다른 엔티티입니다.

ODR 위반은 컴파일러가 진단해야 합니다.다른 위반, 특히 번역 유닛에 걸친 위반은 [1]진단할 필요가 없습니다.

일반적으로 번역단위는 모든 종류의 정의를 1개만 포함할 수 있다.이 예에서는 클래스 타입 C의 2개의 정의가 같은 변환 단위로 이루어집니다.일반적으로 헤더 파일이 적절한 헤더 가드 없이 동일한 소스 파일에 의해 두 번 포함된 경우 이 문제가 발생합니다.

학급 C {}; // C의 첫 번째 정의 학급 C {}; // 오류, C의 두 번째 정의 

다음에서 S에 대한 포인터를 형성하거나 S를 참조하는 함수를 정의하는 것은 S의 유형을 완성할 필요가 없기 때문에 법적 구성의 예이다.따라서 정의는 [2]필요하지 않습니다.

타입 S의 오브젝트의 정의, 타입 S의 인수를 받는 함수, 또는 식 사이즈로 S를 사용하는 것은 S가 완전해야 하기 때문에 [2]정의가 필요한 컨텍스트의 예입니다.

구조 S;     // S 선언 S * p;        // OK, 정의는 필요 없습니다. 무효 f(S&);   // OK, 정의는 필요 없습니다. 무효 f(S*);   // OK, 정의는 필요 없습니다. S f();        // OK, 정의는 필요 없습니다.이것은 함수 선언뿐입니다!  S s;          // 오류, 정의 필요 크기(S);    // 오류, 정의 필요 

복수의 정의

경우에 따라 유형 또는 템플릿에 대한 정의가 여러 개 있을 수 있습니다.여러 헤더 파일과 소스 파일로 구성된 프로그램은 일반적으로 한 유형의 정의를 여러 개 갖지만 변환 단위당 정의를 여러 개 갖출 수 없습니다.

프로그램에 두 개 이상의 유형의 정의가 포함되어 있는 경우 각 정의는 [3]동일해야 합니다.

정적 Const 데이터 멤버의 정의

이전 표준 C++에서는 모든 정적 데이터 멤버는 클래스 외부에서 정의가 필요했습니다.단, C++ 표준화 프로세스 중에 정적 정수 부재에 대한 이 요건을 해제하기로 결정되었습니다.목적은 다음과 같은 사용을 허용하는 것이었다.

구조 C {   정적인 컨스턴트 인트 N = 10; };  데이터.[C::N]; // 클래스 외 정의 없음N "사용" 

네임스페이스 범위 정의 없음N.

그럼에도 불구하고,[4] 1998년 C++ 기준의 문구는 회원이 프로그램에 사용된 경우 정의를 여전히 요구하였다.여기에는 size of 또는 typeid에 대한 피연산자를 제외하고 어디에나 나타나는 멤버가 포함되어 있어 위의 형식이 사실상 [5]잘못되어 있습니다.

이는 결함으로 확인되었으며, 문구를 조정하여 그러한 구성원을 클래스 밖의 정의 없이 일정한 표현이 필요한 곳에 표시할 수 있도록 하였다.여기에는 배열 경계, 대/소문자 표현식, 정적 멤버 이니셜라이저 및 nontype 템플릿 [6]인수가 포함됩니다.

구조 C {   정적인 컨스턴트 인트 N = 10;   정적인 컨스턴트 인트 U = N; // C++03마다 유효 };   데이터.[C::N]; // C++03마다 유효  템플릿< >인트> 구조 D;  템플릿<< 고객명 >>님 구조 D< >C::N> {}; // C++03마다 유효 

단, 정수식이 필요한 경우를 제외하고 임의의 장소에서 정적 const 적분 멤버를 사용하려면 다음과 [7]같은 정의가 필요합니다.

구조 C {   정적인 컨스턴트 인트 N = 10; };  인트 주된() {   인트 i = C::N; // C++03의 형식이 잘못되었습니다.C::N의 정의가 필요합니다. } 

이 요건은 이후 표준인 C++[7]11에서 완화되었다.

예기치 않은 부작용을 나타내는 예

4개의 파일이 필요합니다. "odr.h", "main.cpp", "odr1.cpp", "odr2.cpp"

여기서 "odr"은 "One Definition Rule"의 약자입니다.

odr.h:

// 추상 베이스 클래스 학급 CBase { 일반의:  가상 무효 xxx() = 0;  가상 ~CBase() = 체납; };  외부 CBase *odr1_create(); 외부 CBase *odr2_create(); 

main.cpp

#실패하다 "ocr.h"  인트 주된(인트 argc,  **argv) {  CBase *o1 = odr1_create();  CBase *o2 = odr2_create();  o1->xxx();  o2->xxx(); } 

odr1.cpp

#실패하다 <stdio.h> #실패하다 "ocr.h"  학급 CD미 : 일반의 CBase { 일반의:  무효 xxx() 덮어쓰다 {   인쇄물("ODR ONE 더미:안녕\n");  } };  CBase *odr1_create() {  돌아가다 신규 CD미(); } 

odr2.cpp

#실패하다 <stdio.h> #실패하다 "ocr.h"  학급 CD미 : 일반의 CBase { 일반의:  무효 xxx() 덮어쓰다 {   인쇄물("Odr 2 더미:세계\n");  } };  CBase *odr2_create() {  돌아가다 신규 CD미(); } 

시험삼아 볼 Linux 쉘에서 다음 컴파일을 실시합니다.

g++ -c odr1.cpp g++ -c odr2.cpp g+ -c main.cpp g+ -o dr main.o odr1.o dr2.o

Windows Visual Studio "Build Tools Command Prompt"에서 다음을 사용하여 컴파일합니다.

cl / c main . cpp cl / c odr1 . cpp cl / c odr2 . cpp cl / Feodr . exe main . obj odr1 . obj odr2 . obj

실행 시 예상되는 출력은 다음과 같습니다.

odr ONE 더미:안녕하세요 ODR TWO 더미:세계

하지만 다음과 같은 이점을 얻을 수 있습니다.

odr ONE 더미:안녕하세요 ODR ONE 더미:안녕

문제는 C++ 링커가 (2개의 다른) "CDummy" 클래스의 가상 메서드테이블을 작성하는 방법을 알아내야 한다는 것입니다.이 방법은 클래스 이름이 다른 경우에만 동작합니다.

「 」를 참조해 주세요.

레퍼런스

  1. ^ ISO/IEC(2003)ISO/IEC 14882:2003(E): 프로그래밍 언어 - C++ 3 3.2 정의 규칙 [basic.def.odr]파라 1개3
  2. ^ a b ISO/IEC(2003)ISO/IEC 14882:2003(E): 프로그래밍 언어 - C++ 3 3.2 정의 규칙 [basic.def.odr]파라 1개4
  3. ^ ISO/IEC(2003)ISO/IEC 14882:2003(E): 프로그래밍 언어 - C++ 3 3.2 정의 규칙 [basic.def.odr]파라 1개5
  4. ^ ISO/IEC(1998).ISO/IEC 14882:1998(E): 프로그래밍 언어 - C++ © 9.4.2 정적 데이터 멤버 [class.static.data]파라.4
  5. ^ ISO/IEC(1998).ISO/IEC 14882:1998(E): 프로그래밍 언어 - C++ 3 3.2 정의 규칙 [basic.def.odr]파라 1개2
  6. ^ ISO/IEC(2003)ISO/IEC 14882:2003(E): 프로그래밍 언어 - C++ 5 5.19 상수식 [expr.const] 단락.1
  7. ^ a b "When is a definition of a static data member required?". WG21. Retrieved 2009-04-15.