헤더 전용 라이브러리의 이점


101

헤더 전용 라이브러리의 이점은 무엇이며 구현을 별도의 파일에 넣는 것과 반대되는 방식으로 작성하는 이유는 무엇입니까?


대부분 템플릿이지만 배포 및 사용이 조금 더 쉬워집니다.
BoBTFish

4
질문 범위에 헤더 전용 라이브러리의 단점을 추가하고 싶습니다 ...
moooeeeep

아직 언급하지 않은 단점은 무엇입니까?
NebulaFox

7
@moooeeeep : 단점 으로 C ++ Dos and Don'ts Chromium Projects 웹 페이지의 "Stop inlining code" 단락을 읽어보십시오 .
Mr.C64

답변:


57

헤더 전용 라이브러리가 유일한 옵션 인 상황이 있습니다 (예 : 템플릿을 처리 할 때).

헤더 전용 라이브러리가 있다는 것은 라이브러리가 사용될 수있는 다른 플랫폼에 대해 걱정할 필요가 없음을 의미합니다. 구현을 분리 할 때 일반적으로 구현 세부 정보를 숨기고 라이브러리를 헤더 및 라이브러리 ( lib, dll'또는 .so파일) 의 조합으로 배포합니다 . 물론 지원을 제공하는 모든 운영 체제 / 버전에 맞게 컴파일해야합니다.

구현 파일을 배포 할 수도 있지만 이는 사용자에게 추가 단계 (사용하기 전에 라이브러리 컴파일)를 의미합니다.

물론 이것은 사례 별로 적용됩니다 . 예를 들어 헤더 전용 라이브러리는 때때로 증가합니다.코드 크기 및 컴파일 시간.


6
"헤더 전용 라이브러리가 있다는 것은 라이브러리가 사용될 수있는 다른 플랫폼에 대해 걱정할 필요가 없음을 의미합니다.": 라이브러리를 유지할 필요가없는 경우에만 가능합니다. 그렇지 않으면 가지고있는 자료를 재현하거나 테스트 할 수 없다는 버그 보고서가있는 악몽입니다.
James Kanze

1
헤더 만의 성능 이점에 대해 비슷한 질문을했습니다. 보시다시피 코드 크기에는 차이가 없습니다. 그러나 예제 헤더 전용 구현은 7 % 느리게 실행되었습니다. stackoverflow.com/questions/12290639/…
Homer6

@ Homer6 나를 핑해 주셔서 감사합니다. 나는 이것을 실제로 측정 한 적이 없습니다.
Luchian Grigore 2012

1
@LuchianGrigore 나는 둘 중 하나를 가진 다른 사람을 찾을 수 없습니다. 그래서 대답하는 데 시간이 걸립니다. 추측적인 "코드 크기 증가"및 "메모리 소비"주석이 너무 많습니다. 드디어 차이점에 대한 스냅 샷을 얻었습니다.
Homer6 2011

@ Homer6. 코드 크기가 증가하지 않는 이유는 무엇입니까? 헤더 만 lib 만 사용하는 여러 라이브러리를 만든 다음 앱이 모든 라이브러리를 사용한다고 가정하면 단일 공유 라이브러리에 대한 링크와는 반대로 여러 복사본이 있어야합니다.
pooya13

61

헤더 전용 라이브러리의 이점 :

  • 빌드 프로세스를 단순화합니다. 라이브러리를 빌드 할 필요가 없으며 빌드의 링크 단계 중에 컴파일 된 라이브러리를 지정할 필요가 없습니다. 컴파일 된 라이브러리가있는 경우 여러 버전을 빌드 할 수 있습니다. 하나는 디버깅이 활성화 된 상태로 컴파일되고 다른 하나는 최적화가 활성화 된 상태로 컴파일되고 다른 하나는 심볼이 제거 된 상태 일 수 있습니다. 그리고 아마도 다중 플랫폼 시스템의 경우 더 많을 것입니다.

헤더 전용 라이브러리의 단점 :

  • 더 큰 개체 파일. 일부 소스 파일에서 사용되는 라이브러리의 모든 인라인 메서드는 해당 소스 파일에 대해 컴파일 된 개체 파일에서 약한 기호, 라인 외부 정의를 가져옵니다. 이로 인해 컴파일러 속도가 느려지고 링커 속도도 느려집니다. 컴파일러는 모든 팽창을 생성해야하며 링커는이를 필터링해야합니다.

  • 더 긴 컴파일. 위에서 언급 한 팽창 문제 외에도 헤더가 컴파일 된 라이브러리보다 헤더 전용 라이브러리에서 본질적으로 더 크기 때문에 컴파일 시간이 더 오래 걸립니다. 이러한 큰 헤더는 라이브러리를 사용하는 각 소스 파일에 대해 구문 분석해야합니다. 또 다른 요소는 헤더 전용 라이브러리의 헤더 파일 #include이 인라인 정의에 필요한 헤더와 라이브러리가 컴파일 된 라이브러리로 빌드 된 경우 필요한 헤더를 가져야 한다는 것입니다.

  • 더 복잡한 컴파일. 헤더 전용 라이브러리에 #include필요한 추가 요소 때문에 헤더 전용 라이브러리를 사용하면 더 많은 종속성을 얻을 수 있습니다. 라이브러리에서 일부 주요 기능의 구현을 변경하면 전체 프로젝트를 다시 컴파일해야 할 수도 있습니다. 컴파일 된 라이브러리의 소스 파일을 변경하면 하나의 라이브러리 소스 파일을 다시 컴파일하고 컴파일 된 라이브러리를 새 .o 파일로 업데이트 한 다음 응용 프로그램을 다시 연결하기 만하면됩니다.

  • 인간이 읽기가 더 어렵습니다. 최고의 문서가 있더라도 라이브러리 사용자는 종종 라이브러리의 헤더를 읽어야합니다. 헤더 전용 라이브러리의 헤더는 인터페이스를 이해하는 데 방해가되는 구현 세부 정보로 채워집니다. 컴파일 된 라이브러리를 사용하면 인터페이스와 구현이 수행하는 작업에 대한 간략한 설명 만 볼 수 있으며 일반적으로 원하는 모든 것입니다. 그게 정말 당신이 원하는 전부입니다. 라이브러리 사용 방법을 알기 위해 구현 세부 사항을 알 필요는 없습니다.


22
마지막 요점은 실제로 의미가 없습니다. 합당한 문서에는 함수 선언, 매개 변수, 반환 값 등 및 모든 관련 주석이 포함됩니다. 헤더 파일을 참조해야하는 경우 문서가 실패한 것입니다.
Thomas

6
@Thomas-최고의 전문 라이브러리 라 할지라도 나는 종종 "fine"헤더를 읽는 것에 의지해야하는 자신을 발견합니다. 사실, 소위 "정밀"문서가 코드와 주석에서 추출되면 일반적으로 헤더를 읽는 것을 좋아합니다. 코드와 주석은 자동 생성 된 문서보다 더 많은 것을 알려줍니다.
David Hammen 2014 년

2
마지막 포인트가 유효하지 않습니다. 헤더는 이미 private 멤버의 구현 세부 정보로 채워져 있으므로 cpp 파일이 모든 구현 세부 정보를 숨기는 것과는 다릅니다. 또한, C #을 같은 언어는 기본적으로 디자인하여 "오직 헤더", 그리고 IDE가 (그들을 "접이식") 세부 사항을 모호하게 처리한다
마크 Lakata

2
@Tomas : 동의합니다. 마지막 요점은 완전히 가짜입니다. 헤더 전용 라이브러리와 마찬가지로 인터페이스와 구현을 쉽게 분리 할 수 ​​있습니다. 인터페이스 헤더 #include 구현 세부 정보가 있습니다. 이것이 Boost 라이브러리가 일반적으로라는 하위 디렉토리 (및 네임 스페이스)를 포함하는 이유 detail입니다.
Nemo

4
@Thomas : 동의하지 않습니다. 헤더 파일은 일반적으로 문서화를 위해 가장 먼저가는 곳입니다. 헤더가 잘 작성되어 있으면 외부 문서가 필요하지 않은 경우가 많습니다.
Joel Cornett 2015

15

이것이 오래된 스레드라는 것을 알고 있지만 아무도 ABI 인터페이스 또는 특정 컴파일러 문제를 언급하지 않았습니다. 그래서 그렇게 생각했습니다.

이것은 기본적으로 사람들에게 배포 할 헤더가있는 라이브러리를 작성하거나 헤더에 모든 것을 포함하는 대신 자신을 재사용한다는 개념을 기반으로합니다. 헤더와 소스 파일을 재사용하고 모든 프로젝트에서 재 컴파일 할 생각이라면 실제로 적용되지 않습니다.

기본적으로 C ++ 코드를 컴파일하고 하나의 컴파일러로 라이브러리를 빌드하면 사용자가 다른 컴파일러 또는 동일한 컴파일러의 다른 버전에서 해당 라이브러리를 사용하려고하면 바이너리 비 호환성으로 인해 링커 오류 또는 이상한 런타임 동작이 발생할 수 있습니다.

예를 들어 컴파일러 공급 업체는 종종 버전간에 STL 구현을 변경합니다. 라이브러리에 std :: vector를 받아들이는 함수가있는 경우 해당 클래스의 바이트가 라이브러리가 컴파일 될 때 정렬 된 방식으로 정렬 될 것으로 예상합니다. 새 컴파일러 버전에서 공급 업체가 std :: vector의 효율성을 개선 한 경우 사용자의 코드는 다른 구조를 가질 수있는 새 클래스를보고 새 구조를 라이브러리로 전달합니다. 모든 것이 거기에서 내려갑니다 ... 이것이 라이브러리 경계를 넘어 STL 객체를 전달하지 않는 것이 권장되는 이유입니다. CRT (C 런타임) 유형에도 동일하게 적용됩니다.

CRT에 대해 이야기하는 동안 라이브러리와 사용자의 소스 코드는 일반적으로 동일한 CRT에 연결되어야합니다. Visual Studio에서 다중 스레드 CRT를 사용하여 라이브러리를 빌드하지만 사용자가 다중 스레드 디버그 CRT에 대해 링크하면 라이브러리가 필요한 기호를 찾지 못할 수 있으므로 링크 문제가 발생합니다. 어떤 기능인지 기억이 나지 않지만 Visual Studio 2015의 경우 Microsoft는 하나의 CRT 기능을 인라인으로 만들었습니다. 갑자기 CRT 라이브러리가 아닌 헤더에 있었기 때문에 링크 타임에 찾을 것으로 예상했던 라이브러리가 더 이상 할 수 없었고 이로 인해 링크 오류가 발생했습니다. 그 결과 이러한 라이브러리는 Visual Studio 2015로 다시 컴파일해야했습니다.

Windows API를 사용하지만 라이브러리 사용자에 대해 다른 유니 코드 설정으로 빌드하는 경우에도 링크 오류 또는 이상한 동작이 발생할 수 있습니다. 이는 Windows API에 유니 코드 또는 ASCII 문자열을 사용하는 함수와 프로젝트의 유니 코드 설정에 따라 올바른 유형을 자동으로 사용하는 매크로 / 정의가 있기 때문입니다. 잘못된 유형 인 라이브러리 경계를 넘어서 문자열을 전달하면 런타임에 문제가 발생합니다. 또는 프로그램이 처음에 연결되지 않음을 알 수 있습니다.

이러한 사항은 다른 타사 라이브러리 (예 : Eigen 벡터 또는 GSL 행렬)에서 라이브러리 경계를 넘어 객체 / 유형을 전달하는 경우에도 적용됩니다. 타사 라이브러리가 라이브러리를 컴파일하고 사용자가 코드를 컴파일하는 사이에 헤더를 변경하면 문제가 발생합니다.

기본적으로 안전을 위해 라이브러리 경계를 넘어 전달할 수있는 유일한 것은 유형과 POD (Plain Old Data)에 내장되어 있습니다. 이상적으로 모든 POD는 자체 헤더에 정의 된 구조체에 있어야하며 타사 헤더에 의존하지 않아야합니다.

헤더 전용 라이브러리를 제공하면 모든 코드가 동일한 컴파일러 설정 및 동일한 헤더에 대해 컴파일되므로 이러한 많은 문제가 해결됩니다 (사용자와 사용자가 사용하는 세 번째 라이브러리의 버전이 API 호환 가능).

그러나 컴파일 시간 증가와 같은 위에서 언급 한 부정적 요소가 있습니다. 또한 비즈니스를 운영하고 있으므로 사용자 중 한 명이 훔치는 경우 모든 소스 코드 구현 세부 정보를 모든 사용자에게 전달하고 싶지 않을 수 있습니다.


8

주된 "이점"은 소스 코드를 제공해야한다는 것입니다. 따라서 컴퓨터와 컴파일러에 대한 오류보고가 발생합니다. 라이브러리가 완전히 템플릿 인 경우 선택의 여지가 많지 않지만 선택할 수있는 경우 헤더 만 일반적으로 엔지니어링 선택이 좋지 않습니다. (반면에 헤더는 통합 절차를 문서화 할 필요가 없음을 의미 할뿐입니다.)


0

인라인은 LTO (Link Time Optimization)로 수행 할 수 있습니다.

헤더 전용 라이브러리의 두 가지 주요 이점 중 하나 인 "인라인으로 처리 할 헤더에 대한 정의가 필요합니다."라는 두 가지 주요 이점 중 하나의 값을 감소시키기 때문에 이것을 강조하고 싶습니다.

이에 대한 최소한의 구체적인 예는 링크 시간 최적화 및 인라인에 나와 있습니다.

따라서 플래그를 전달하기 만하면 리팩토링 작업없이 개체 파일 전체에서 인라인을 수행 할 수 있습니다. 더 이상 헤더에 정의를 유지할 필요가 없습니다.

그러나 LTO에도 단점 이있을 수 있습니다. 링크 시간 최적화 (LTO)를 사용하지 않는 이유가 있습니까?

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.