2010-12-08 5 views
3

메소드 정의가 헤더 파일에있는 동안 별도의 C++에 배치 된 클래스에 대한 코드를 보았습니다. 내 첫 번째 OOP 경험은 Java와 함께 모든 메서드가 클래스 파일에 배치되며, 실제로 이것을 선호합니다..h 대 .cpp 파일로 메소드 배치하기

내 모든 메서드를 헤더 파일에 배치하면 컴파일러에서 생성 된 어셈블리 코드에 영향을 주는지 여부가 결정됩니까?

그렇다면 클래스의 전체 코드를 헤더 파일에 배치하는 것이 성능에 전혀 해로운 것입니까?

답변

2

헤더/구현 분할 및 별도의 컴파일에 대한 몇 가지 유효한 이유가있어 :
작업 요구 될 수있다 (1) - 예를 들어, 누군가에 바이너리 라이브러리 + 헤더를 공급하고, 또는 동료는 너무 보수적이어서 다른 것을 받아들이는 입니다.
2. 수정할 때마다 전체 응용 프로그램을 다시 작성하기 때문에 여전히 매우 큰 프로젝트 (예 : 10M> 원본) 인 을 개발해야합니다. (하지만 jpeglib 또는 zlib 같은 모듈을 단일 모듈로 컴파일해도 괜찮습니다.)
3. 참조 파일로 사용하기 쉬운 헤더 파일은 up functions 등입니다. (그러나 일반적으로 적절한 문서를 작성하는 것이 좋습니다. 헤더와 달리 문서의 버그가 프로그램에 영향을 미치지 않습니다.

더 이상 사용하지 않는 이유가 더 있습니다.
1. 중복 된 코드를 유지하는 것을 피하려면
2. 클래스 메서드는 전달 선언이 필요하지 않습니다.
3. 템플릿은 헤더에 대해서만 선언 할 수 있습니다.
4.함수 인라이닝이 필요하지 않은 경우는 실제로는 매우 희귀합니다. 즉 대규모 함수를 긴 루프에서 여러 번 호출하는 경우가 있지만noinline 속성과 PGO가 있습니다. 그렇지 않으면 인라인이 속도를 향상시킵니다. 그리고 코드가 부 풀리면 대부분의 라이브러리가 이미 거대합니다.
5. 컴파일러가 더 나은 작업을 수행 할 수 있기 때문에 전반적으로 단일 소스로 컴파일 된 프로그램은 더 작고 더 짧습니다. .
6. 헤더가 없으면 소스가 빈번하게 두 번 더 작아집니다. 및 컴파일러가 구문을 올바르게 확인할 수 있으므로 이 실수로 extern "C"cdecl 함수 프로토 타입을 변수에 연결할 수 없습니다 구현으로. 또한 링커마다 이름 일치에 대한 아이디어가 다르기 때문에 전체적으로 더 이식성이 좋습니다.
7. 이상하지만 동적 인 할당은 헤더 스타일 때문에 자주 사용됩니다. 세부 정보를 단일 클래스 내에 모두 정의하여 종속성을 자동으로 해결할 수 있지만 대신 부분 클래스 선언에 대한 포인터를 사용하는 것이 좋습니다. 사냥 메모리 누수).

개별 객체 모듈에 대한 몇 가지 보너스 포인트가 있습니다 :
4. gcc의 PGO 통계는 하나의 실행 파일로 몇 가지 다른 작업 모드를 "벤치마킹"하는 유일한 방법 인 것처럼 보이는 객체 모듈 당 생성됩니다.
5. 속도 최적화를 위해 다른 컴파일러 옵션으로 다른 모듈을 컴파일 할 수 있습니다. 또한 컴파일러 확장도 있지만 신뢰할 만하지는 않습니다.
6. 뭔가를 수정할 때 컴파일러가 코드의 다른 부분에 이상한 것을 할 수 있지만 대개는 개체 모듈 외부로 전파 할 수 없습니다.

6

요점은 복잡한 C++ 프로그램은 여러 개체를 컴파일 한 다음 함께 연결한다는 점입니다. 각 객체는 일반적으로 많은 헤더를 직접 및 간접적으로 포함 할 수있는 하나의 구현 파일 (예 : ".cpp", ".cc"등)을 컴파일하여 생성됩니다. 결과적으로, 좋은 클래스를 작성하고 헤더에 코드를 넣으면 그 코드는 여러 개의 오브젝트 파일에 포함될 수 있고 컴파일러는이를 중복 생성하고 추가적으로 링커는 (그리고 쉽게) 비교할 수 없습니다 두 버전이 동등한 지 확인하고 중복 사본을 제거 할 수 있습니다 (상대적 주소 - "위치 독립적 코드"를 사용하는 것이 더 쉽지만 - 다른 이야기입니다). 아래의 jalf의 의견도 참조하십시오.

그래서 헤더에 다른 라인 외부 기능을 원하지 않습니다. 만약 그들이 명목상으로 inline 함수라면 - 인라인 키워드를 사용하거나 클래스 내부에 정의되어 있기 때문에 컴파일러는 추가 작업을 수행하고 라인 외 버전이 실행 파일. 그러나 라인 밖 함수의 경우 프로그래머에게는 부담이 남아 있습니다.

또한 헤더에 구현을 제공하면 각 객체에 대해 중복 컴파일되고 헤더를 변경하면 모든 종속 객체가 강제로 다시 컴파일됩니다. 별도의 개체에서 라인 외부 기능을 변경하고 단일 개체를 다시 컴파일 한 다음 다른 기존 개체와 연결하여 새로운 실행 파일을 만들 수 있습니다. 대규모 프로젝트에서는 많은 컴파일 시간을 절약 할 수 있습니다.

+1

+1 정말 답이 맘에 들어요. 그러나 호기심에서 템플릿에 대한 생각은 무엇입니까? 필자는 많은 템플릿 코드가 여분의 "인라인"헤더를 포함하거나 메소드의 거대한 혼란을 겪고 있음을 보았습니다. – GWW

+1

@GWW : 템플릿은 각 유형의 조합에 대해 인스턴스화되므로 매우 빠르고 강력하지만 클라이언트 코드에 크게 의존합니다. C++ 역사를 통틀어 아무도 헤더를 통해 "구현"을 노출 할 필요가 없도록하는 좋은 방법을 발견했습니다. 다른 파일을 #include하는 것은 때때로 클래스/구조체 선언 후에 함수 정의를 넣을 때와 마찬가지로 API를 별도로 유지하는 데 도움이되지만 최적의 결과는 여러 요소 (함수 길이, 문서의 크기 및 양, 복잡성, 번호/기술 클라이언트 사용자 대 구현 유지 자). 그것은 * 지저분합니다 :-) –

+0

링커는 클래스 정의의 두 인스턴스가 동일한 지 (그리고 그렇게하는 링커를 모르는지) 확인할 필요가 없습니다. 이름이 같은 경우 일반적으로 * 동일하다고 가정하고 둘 중 하나를 제거합니다. 프로그래머는 항상 ODR을 위반하지 않아도됩니다. – jalf

1

예, 헤더에 삽입 된 메소드는 인라인되어 있으므로 일반적으로 빠릅니다 (특히 짧은 메소드).

주요 단점은 헤더를 수정할 때마다 헤더를 포함하는 각 파일을 다시 컴파일해야하기 때문입니다.

+0

"헤더에 삽입 된 메소드는 인라인됩니다."- 숙련 된 C++ 프로그래머 코드에서 그렇지만 초보자 (예 : seljuq70)는 헤더에 비 인라인 함수를 넣는 실수를 저지르는 경우가 많습니다. 전문적으로,'class' /'struct' 내부에 정의 된 (즉, 그들의 몸체와 함께) 함수들, 또는'inline' 키워드를 지정하는 함수들만 인라인됩니다. 그것들은 머리말의 유일한 기능이어야하지만 그렇지 않을 수도 있습니다. –

+0

@ 토니 : 그래서 내가 당신의보다 상세한 답변에 투표했습니다. 그러나 그들이 보통 짧은 기능 *을 갖는 것이 가장 좋습니다. – ruslik

+0

글쎄, 나는 그곳에서 당신의 관점을 좋아한다. "헤더의 간단한 기능"은 초보자가 사용하기에 너무 간단하지 않은 간단한 지침서이다 - 어쨌든 재 컴파일 설명에 의해 다루어진다. +1. –

관련 문제