Lợi ích của thư viện chỉ dành cho tiêu đề


98

Lợi ích của thư viện chỉ tiêu đề là gì và tại sao bạn lại viết nó theo cách đó phản đối việc đưa triển khai vào tệp riêng biệt?


Chủ yếu là các mẫu, nhưng nó cũng sẽ giúp phân phối và sử dụng dễ dàng hơn một chút.
BoBTFish

4
Tôi muốn thêm nhược điểm của một thư viện tiêu đề chỉ đến phạm vi của câu hỏi ...
moooeeeep

Những nhược điểm nào chưa được đề cập đến?
NebulaFox

7
@moooeeeep: đối với nhược điểm, bạn có thể muốn đọc đoạn "Dừng mã nội tuyến" trong trang web C ++ Dos và Không nên Chromium Projects.
Mr.C64

Câu trả lời:


57

Có những tình huống khi thư viện chỉ có tiêu đề là lựa chọn duy nhất, chẳng hạn như khi xử lý các mẫu.

Có thư viện chỉ dành cho tiêu đề cũng có nghĩa là bạn không phải lo lắng về các nền tảng khác nhau nơi thư viện có thể được sử dụng. Khi bạn tách việc triển khai, bạn thường làm như vậy để ẩn chi tiết triển khai và phân phối thư viện dưới dạng kết hợp của tiêu đề và thư viện ( lib, dllhoặc .sotệp). Tất nhiên, chúng phải được biên dịch cho tất cả các hệ điều hành / phiên bản khác nhau mà bạn cung cấp hỗ trợ.

Bạn cũng có thể phân phối các tệp triển khai, nhưng điều đó có nghĩa là một bước bổ sung cho người dùng - biên dịch thư viện của bạn trước khi sử dụng nó.

Tất nhiên, điều này áp dụng cho từng trường hợp cụ thể. Ví dụ: các thư viện chỉ dành cho tiêu đề đôi khi tăngkích thước mã & thời gian biên dịch.


6
"Có thư viện chỉ dành cho tiêu đề cũng có nghĩa là bạn không phải lo lắng về các nền tảng khác nhau nơi thư viện có thể được sử dụng": chỉ khi bạn không phải duy trì thư viện. Nếu không, đó là một cơn ác mộng, với các báo cáo lỗi mà bạn không thể tái tạo hoặc kiểm tra trên tài liệu bạn có.
James Kanze

1
Tôi vừa hỏi một câu hỏi tương tự về lợi ích hiệu suất của tiêu đề mà thôi. Như bạn có thể thấy, không có sự khác biệt về kích thước mã. Tuy nhiên, việc triển khai chỉ tiêu đề ví dụ chạy chậm hơn 7%. stackoverflow.com/questions/12290639/…
Homer 6

@ Homer6 cảm ơn đã ping cho tôi. Tôi chưa bao giờ thực sự đo được điều này.
Luchian Grigore,

1
@LuchianGrigore Tôi không thể tìm thấy ai khác có. Đó là lý do tại sao phải mất một lúc để trả lời. Có rất nhiều bình luận suy đoán "tăng kích thước mã" và "tiêu thụ bộ nhớ". Cuối cùng tôi cũng có một bản chụp nhanh về sự khác biệt, ngay cả khi đó chỉ là một ví dụ.
Homer

@ Homer6. Tại sao nó không tăng kích thước mã? Giả sử bạn tạo nhiều lib chỉ sử dụng tiêu đề lib và sau đó ứng dụng của bạn sử dụng tất cả các lib đó, bạn sẽ phải có nhiều bản sao thay vì liên kết với một thư viện được chia sẻ.
pooya13

60

Lợi ích của thư viện chỉ dành cho tiêu đề:

  • Đơn giản hóa quá trình xây dựng. Bạn không cần phải xây dựng thư viện và bạn không cần chỉ định thư viện đã biên dịch trong bước liên kết của quá trình xây dựng. Nếu bạn có một thư viện đã biên dịch, bạn có thể sẽ muốn xây dựng nhiều phiên bản của nó: Một phiên bản được biên dịch có bật gỡ lỗi, một phiên bản khác có bật tính năng tối ưu hóa và có thể là một phiên bản khác bị tước bỏ các ký hiệu. Và thậm chí có thể nhiều hơn nữa đối với hệ thống đa nền tảng.

Nhược điểm của thư viện chỉ có tiêu đề:

  • Tệp đối tượng lớn hơn. Mọi phương thức nội tuyến từ thư viện được sử dụng trong một số tệp nguồn cũng sẽ nhận được một ký hiệu yếu, định nghĩa ngoài dòng trong tệp đối tượng đã biên dịch cho tệp nguồn đó. Điều này làm chậm trình biên dịch và cũng làm chậm trình liên kết. Trình biên dịch phải tạo ra tất cả những thứ đó, và sau đó trình liên kết phải lọc nó ra.

  • Biên dịch dài hơn. Ngoài vấn đề cồng kềnh được đề cập ở trên, quá trình biên dịch sẽ mất nhiều thời gian hơn vì các tiêu đề vốn có dung lượng lớn hơn với thư viện chỉ dành cho tiêu đề so với thư viện đã biên dịch. Các tiêu đề lớn đó sẽ cần được phân tích cú pháp cho từng tệp nguồn sử dụng thư viện. Một yếu tố khác là các tệp tiêu đề đó trong thư viện chỉ dành cho #includetiêu đề phải có các tiêu đề cần thiết bởi các định nghĩa nội tuyến cũng như các tiêu đề cần thiết nếu thư viện được xây dựng như một thư viện đã biên dịch.

  • Biên dịch rối hơn. Bạn nhận được nhiều phụ thuộc hơn với thư viện chỉ có tiêu đề vì những thứ bổ sung #includeđó cần thiết với thư viện chỉ có tiêu đề. Thay đổi việc triển khai một số chức năng chính trong thư viện và bạn có thể cần phải biên dịch lại toàn bộ dự án. Thực hiện thay đổi đó trong tệp nguồn cho một thư viện đã biên dịch và tất cả những gì bạn phải làm là biên dịch lại một tệp nguồn thư viện đó, cập nhật thư viện đã biên dịch với tệp .o mới đó và liên kết lại ứng dụng.

  • Khó hơn cho con người để đọc. Ngay cả khi có tài liệu tốt nhất, người sử dụng thư viện đôi khi phải dùng đến việc đọc các tiêu đề cho thư viện. Các tiêu đề trong thư viện chỉ dành cho tiêu đề chứa đầy các chi tiết triển khai cản trở việc hiểu giao diện. Với một thư viện đã biên dịch, tất cả những gì bạn thấy là giao diện và bình luận ngắn gọn về những gì việc triển khai thực hiện và đó thường là tất cả những gì bạn muốn. Đó thực sự là tất cả những gì bạn nên muốn. Bạn không cần phải biết chi tiết triển khai để biết cách sử dụng thư viện.


21
Điểm cuối cùng không thực sự có ý nghĩa. Bất kỳ tài liệu hợp lý nào sẽ bao gồm khai báo hàm, tham số, giá trị trả về, v.v. và tất cả các nhận xét liên quan. Nếu bạn phải tham chiếu đến tệp tiêu đề, tài liệu đã bị lỗi.
Thomas

6
@Thomas - Ngay cả với những thư viện chuyên nghiệp tốt nhất, đôi khi tôi thấy mình phải dùng đến cách đọc tiêu đề "tốt". Trên thực tế, nếu tài liệu được gọi là "tốt" được trích xuất từ ​​mã cộng với bình luận, tôi thường thích đọc tiêu đề. Mã cộng với các nhận xét cho tôi biết nhiều điều hơn là tài liệu được tạo tự động.
David Hammen

2
Điểm cuối cùng không hợp lệ. Tiêu đề đã được điền đầy đủ các chi tiết triển khai trong các thành viên riêng tư, vì vậy nó không giống như tệp cpp ẩn tất cả các chi tiết triển khai. Bên cạnh đó, các ngôn ngữ như C # cơ bản là "chỉ tiêu đề" bởi thiết kế, và IDE chăm sóc che khuất chi tiết ( "gấp" chúng xuống)
Đánh dấu Lakata

2
@Tomas: Đồng ý, điểm cuối cùng hoàn toàn không có thật. Bạn có thể dễ dàng giữ giao diện và triển khai riêng biệt với các thư viện chỉ dành cho tiêu đề; bạn chỉ cần có tiêu đề giao diện #include chi tiết triển khai. Đây là lý do tại sao các thư viện Boost thường bao gồm một thư mục con (và không gian tên) được gọi detail.
Nemo

4
@Thomas: Tôi không đồng ý. Tệp tiêu đề thường là nơi đầu tiên tôi đến để lấy tài liệu. Nếu tiêu đề được viết tốt, thường không cần tài liệu bên ngoài.
Joel Cornett

14

Tôi biết đây là một chủ đề cũ, nhưng không ai đề cập đến giao diện ABI hoặc các vấn đề trình biên dịch cụ thể. Vì vậy, tôi nghĩ tôi sẽ làm.

Điều này về cơ bản dựa trên khái niệm về việc bạn viết một thư viện với tiêu đề để phân phối cho mọi người hoặc tự sử dụng lại so với có mọi thứ trong tiêu đề. Nếu bạn đang nghĩ đến việc sử dụng lại tiêu đề và tệp nguồn và biên dịch lại chúng trong mọi dự án thì điều này không thực sự áp dụng.

Về cơ bản, nếu bạn biên dịch mã C ++ của mình và xây dựng một thư viện với một trình biên dịch thì người dùng cố gắng sử dụng thư viện đó với một trình biên dịch khác hoặc một phiên bản khác của cùng một trình biên dịch thì bạn có thể gặp lỗi trình liên kết hoặc hành vi thời gian chạy lạ do không tương thích nhị phân.

Ví dụ, các nhà cung cấp trình biên dịch thường thay đổi việc triển khai STL giữa các phiên bản. Nếu bạn có một hàm trong thư viện chấp nhận một vectơ std :: thì nó mong đợi các byte trong lớp đó được sắp xếp theo cách chúng được sắp xếp khi thư viện được biên dịch. Nếu, trong phiên bản trình biên dịch mới, nhà cung cấp đã thực hiện các cải tiến về hiệu quả đối với std :: vector thì mã của người dùng sẽ thấy lớp mới có thể có cấu trúc khác và chuyển cấu trúc mới đó vào thư viện của bạn. Mọi thứ đi xuống dốc từ đó ... Đây là lý do tại sao không nên chuyển các đối tượng STL qua ranh giới thư viện. Điều tương tự cũng áp dụng cho các loại C Run-Time (CRT).

Trong khi nói về CRT, thư viện của bạn và mã nguồn của người dùng thường cần được liên kết với cùng một CRT. Với Visual Studio nếu bạn xây dựng thư viện của mình bằng CRT đa luồng, nhưng người dùng liên kết với CRT gỡ lỗi đa luồng thì bạn sẽ gặp sự cố liên kết vì thư viện của bạn có thể không tìm thấy các ký hiệu mà nó cần. Tôi không thể nhớ đó là chức năng nào, nhưng đối với Visual Studio 2015, Microsoft đã tạo một hàm CRT nội tuyến. Đột nhiên, nó nằm trong tiêu đề không phải là thư viện CRT nên các thư viện mong đợi tìm thấy nó tại thời điểm liên kết không thể thực hiện được nữa và điều này đã tạo ra lỗi liên kết. Kết quả là các thư viện này cần biên dịch lại với Visual Studio 2015.

Bạn cũng có thể gặp lỗi liên kết hoặc hành vi lạ nếu bạn sử dụng Windows API nhưng bạn xây dựng với các cài đặt Unicode khác nhau cho người dùng thư viện. Điều này là do Windows API có các hàm sử dụng chuỗi Unicode hoặc ASCII và macro / xác định tự động sử dụng đúng loại dựa trên cài đặt Unicode của dự án. Nếu bạn truyền một chuỗi qua ranh giới thư viện không đúng loại thì mọi thứ sẽ bị hỏng trong thời gian chạy. Hoặc bạn có thể thấy rằng chương trình không liên kết ngay từ đầu.

Những điều này cũng đúng khi chuyển các đối tượng / kiểu qua ranh giới thư viện từ các thư viện bên thứ ba khác (ví dụ: vectơ Eigen hoặc ma trận GSL). Nếu thư viện bên thứ 3 thay đổi tiêu đề của họ giữa bạn biên dịch thư viện và người dùng của bạn biên dịch mã của họ thì mọi thứ sẽ hỏng.

Về cơ bản để an toàn, những thứ duy nhất bạn có thể vượt qua ranh giới thư viện được xây dựng theo kiểu và Dữ liệu cũ thuần túy (POD). Lý tưởng nhất là bất kỳ POD nào cũng phải có cấu trúc được xác định trong tiêu đề của riêng bạn và không dựa vào bất kỳ tiêu đề nào của bên thứ ba.

Nếu bạn cung cấp thư viện chỉ tiêu đề thì tất cả mã sẽ được biên dịch với cùng cài đặt trình biên dịch và chống lại cùng tiêu đề, do đó rất nhiều vấn đề này sẽ biến mất (cung cấp phiên bản thư viện phần thứ ba mà bạn và người dùng của bạn sử dụng tương thích với API).

Tuy nhiên có những tiêu cực đã được đề cập ở trên, chẳng hạn như thời gian biên soạn tăng lên. Ngoài ra, bạn có thể đang điều hành một doanh nghiệp vì vậy bạn có thể không muốn giao tất cả các chi tiết triển khai mã nguồn của mình cho tất cả người dùng của bạn trong trường hợp một trong số họ lấy cắp nó.


8

"Lợi ích" chính là nó yêu cầu bạn cung cấp mã nguồn, vì vậy bạn sẽ kết thúc với các báo cáo lỗi trên máy và với các trình biên dịch mà bạn chưa từng nghe đến. Khi thư viện hoàn toàn là các mẫu, bạn không có nhiều lựa chọn, nhưng khi bạn có lựa chọn, chỉ tiêu đề thường là một lựa chọn kỹ thuật kém. (Mặt khác, tất nhiên, tiêu đề chỉ có nghĩa là bạn không phải ghi lại bất kỳ thủ tục tích hợp nào.)


0

Nội tuyến có thể được thực hiện bằng Tối ưu hóa thời gian liên kết (LTO)

Tôi muốn nhấn mạnh điều này vì nó làm giảm giá trị của một trong hai ưu điểm chính của thư viện chỉ tiêu đề: "bạn cần định nghĩa trên tiêu đề để nội dòng".

Một ví dụ cụ thể tối thiểu về điều này được hiển thị tại: Tối ưu hóa thời gian liên kết và nội tuyến

Vì vậy, bạn chỉ cần vượt qua một cờ và nội tuyến có thể được thực hiện trên các tệp đối tượng mà không cần bất kỳ công việc tái cấu trúc nào, không cần phải giữ các định nghĩa trong tiêu đề cho điều đó nữa.

Tuy nhiên, LTO cũng có thể có những nhược điểm riêng: Có lý do gì không sử dụng tối ưu hóa thời gian liên kết (LTO)?

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.