Manfaat pustaka khusus header


101

Apa manfaat dari pustaka hanya header dan mengapa Anda menulisnya seperti itu dan menentang penerapannya ke dalam file terpisah?


Sebagian besar template, tetapi juga akan membuatnya lebih mudah untuk didistribusikan dan digunakan.
BoBTFish

4
Saya ingin menambahkan kelemahan dari perpustakaan hanya-header ke ruang lingkup pertanyaan ...
moooeeeep

Apa kerugian yang belum disebutkan?
NebulaFox

7
@moooeeeep: untuk kelemahannya, Anda mungkin ingin membaca paragraf "Hentikan kode sebaris" di halaman web Proyek Chromium C ++ Anjuran dan Larangan .
Tn. C64

Jawaban:


57

Ada situasi ketika pustaka hanya header adalah satu-satunya pilihan, misalnya ketika berurusan dengan templat.

Memiliki pustaka khusus header juga berarti Anda tidak perlu khawatir tentang berbagai platform tempat pustaka tersebut mungkin digunakan. Saat Anda memisahkan implementasi, Anda biasanya melakukannya untuk menyembunyikan detail implementasi, dan mendistribusikan pustaka sebagai kombinasi header dan pustaka ( lib, dllatau .sofile). Ini tentu saja harus dikompilasi untuk semua sistem operasi / versi berbeda yang Anda tawarkan dukungan.

Anda juga dapat mendistribusikan file implementasi, tetapi itu berarti langkah ekstra bagi pengguna - mengompilasi perpustakaan Anda sebelum menggunakannya.

Tentu saja, ini berlaku atas dasar kasus per kasus . Misalnya, pustaka khusus header terkadang meningkatukuran kode & waktu kompilasi.


6
"Memiliki pustaka hanya-header juga berarti Anda tidak perlu khawatir tentang platform yang berbeda tempat pustaka mungkin digunakan": hanya jika Anda tidak harus memelihara pustaka. Jika tidak, ini adalah mimpi buruk, dengan laporan bug yang tidak dapat Anda tiru atau uji pada materi yang Anda miliki.
James Kanze

1
Saya baru saja mengajukan pertanyaan serupa tentang manfaat kinerja tajuk saja. Seperti yang Anda lihat, tidak ada perbedaan ukuran kode. Namun, contoh penerapan hanya header berjalan 7% lebih lambat. stackoverflow.com/questions/12290639/…
Homer6

@ Homer6 terima kasih telah menge-ping saya. Saya tidak pernah benar-benar mengukur ini.
Luchian Grigore

1
@LuchianGrigore Saya tidak bisa menemukan orang lain yang memilikinya. Karena itulah butuh beberapa saat untuk menjawab. Ada begitu banyak komentar spekulatif "peningkatan ukuran kode" dan "konsumsi memori". Saya akhirnya memiliki gambaran tentang perbedaannya, meskipun itu hanya satu contoh.
Homer6

@Homer. Mengapa itu tidak meningkatkan ukuran kode? Dengan asumsi Anda membuat beberapa lib yang menggunakan lib hanya header dan kemudian aplikasi Anda menggunakan semua lib tersebut, Anda harus memiliki banyak salinan daripada menautkan ke satu pustaka bersama.
pooya13

61

Manfaat pustaka hanya header:

  • Menyederhanakan proses build. Anda tidak perlu mem-build library, dan tidak perlu menentukan library yang dikompilasi selama langkah penautan dalam build. Jika Anda memiliki pustaka terkompilasi, Anda mungkin ingin membangun beberapa versinya: Satu dikompilasi dengan debugging diaktifkan, yang lain dengan pengoptimalan diaktifkan, dan mungkin satu lagi simbol yang dilucuti. Dan mungkin lebih untuk sistem multi-platform.

Kekurangan dari pustaka hanya header:

  • File objek yang lebih besar. Setiap metode inline dari pustaka yang digunakan dalam beberapa file sumber juga akan mendapatkan simbol yang lemah, definisi out-of-line dalam file objek yang dikompilasi untuk file sumber tersebut. Ini memperlambat kompiler dan juga memperlambat linker. Kompiler harus menghasilkan semua penggembungan itu, dan kemudian linker harus memfilternya.

  • Kompilasi lebih lama. Selain masalah bloat yang disebutkan di atas, kompilasi akan memakan waktu lebih lama karena header secara inheren lebih besar dengan library khusus header daripada library yang dikompilasi. Header besar itu perlu diurai untuk setiap file sumber yang menggunakan pustaka. Faktor lainnya adalah bahwa file-file header dalam perpustakaan hanya-header harus #includeheader yang dibutuhkan oleh definisi inline serta header yang akan dibutuhkan seandainya perpustakaan dibangun sebagai perpustakaan yang dikompilasi.

  • Kompilasi yang lebih kusut. Anda mendapatkan lebih banyak dependensi dengan pustaka hanya-header karena tambahan #includeitu diperlukan dengan pustaka hanya-header. Ubah implementasi beberapa fungsi kunci di perpustakaan dan Anda mungkin perlu mengkompilasi ulang seluruh proyek. Buat perubahan itu dalam file sumber untuk pustaka yang dikompilasi dan yang harus Anda lakukan adalah mengompilasi ulang satu file sumber pustaka itu, memperbarui pustaka yang dikompilasi dengan file .o baru, dan menautkan ulang aplikasi.

  • Lebih sulit bagi manusia untuk membaca. Bahkan dengan dokumentasi terbaik, pengguna perpustakaan seringkali harus membaca header perpustakaan. Header di pustaka hanya header diisi dengan detail implementasi yang menghalangi pemahaman antarmuka. Dengan pustaka terkompilasi, yang Anda lihat hanyalah antarmuka dan komentar singkat tentang apa yang dilakukan implementasi, dan biasanya hanya itu yang Anda inginkan. Hanya itu yang Anda inginkan. Anda tidak perlu mengetahui detail implementasi untuk mengetahui cara menggunakan library.


22
Poin terakhir tidak terlalu masuk akal. Setiap dokumentasi yang masuk akal akan menyertakan deklarasi fungsi, parameter, nilai kembalian, dll .. dan semua komentar terkait. Jika Anda harus merujuk ke file header, dokumentasi telah gagal.
Thomas

6
@ Thomas - Bahkan dengan perpustakaan profesional terbaik, saya sering kali harus membaca tajuk yang "bagus". Faktanya, jika apa yang disebut dokumentasi "fine" diekstrak dari kode plus komentar, saya biasanya suka membaca header. Kode plus komentar memberi tahu saya lebih dari sekadar dokumentasi yang dibuat secara otomatis.
David Hammen

2
Poin terakhir tidak valid. Header sudah diisi dengan detail implementasi di private member, jadi tidak seperti file cpp yang menyembunyikan semua detail implementasi. Selain itu, bahasa seperti C # pada dasarnya "hanya header" menurut desain, dan IDE menangani detail yang tidak jelas ("melipat" ke bawah)
Mark Lakata

2
@ Tomas: Setuju, poin terakhir benar-benar palsu. Anda dapat dengan mudah menjaga antarmuka dan implementasi sama terpisahnya dengan pustaka khusus header; Anda cukup memiliki tajuk antarmuka #include detail implementasi. Inilah sebabnya mengapa pustaka Boost biasanya menyertakan subdirektori (dan namespace) yang dipanggil detail.
Nemo

4
@ Thomas: Saya tidak setuju. File header umumnya adalah tempat pertama yang saya kunjungi untuk dokumentasi. Jika tajuk ditulis dengan baik, seringkali tidak diperlukan dokumentasi eksternal.
Joel Cornett

15

Saya tahu ini adalah utas lama, tetapi tidak ada yang menyebutkan antarmuka ABI atau masalah kompiler tertentu. Jadi saya pikir saya akan melakukannya.

Ini pada dasarnya didasarkan pada konsep Anda menulis perpustakaan dengan tajuk untuk didistribusikan ke orang-orang atau menggunakan kembali diri Anda sendiri vs memiliki semuanya di tajuk. Jika Anda berpikir untuk menggunakan kembali header dan file sumber dan mengkompilasi ulang ini di setiap proyek maka ini tidak berlaku.

Pada dasarnya jika Anda mengompilasi kode C ++ dan membangun pustaka dengan satu kompiler, maka pengguna mencoba menggunakan pustaka tersebut dengan kompiler berbeda atau versi berbeda dari kompilator yang sama, maka Anda mungkin mendapatkan kesalahan penaut atau perilaku runtime yang aneh karena ketidakcocokan biner.

Misalnya vendor kompilator sering mengubah implementasi STL mereka antar versi. Jika Anda memiliki fungsi di pustaka yang menerima std :: vector maka itu mengharapkan byte di kelas itu diatur dengan cara yang diatur saat pustaka dikompilasi. Jika, dalam versi kompilator baru, vendor telah melakukan peningkatan efisiensi pada std :: vector maka kode pengguna akan melihat kelas baru yang mungkin memiliki struktur berbeda dan meneruskan struktur baru itu ke perpustakaan Anda. Semuanya berjalan menurun dari sana ... Inilah mengapa disarankan untuk tidak melewatkan objek STL melintasi batas perpustakaan. Hal yang sama berlaku untuk jenis C Run-Time (CRT).

Saat berbicara tentang CRT, pustaka Anda dan kode sumber pengguna umumnya perlu ditautkan ke CRT yang sama. Dengan Visual Studio jika Anda membangun perpustakaan Anda menggunakan CRT Multithread, tetapi link pengguna terhadap Multithreaded Debug CRT maka Anda akan memiliki masalah link karena perpustakaan Anda mungkin tidak menemukan simbol yang dibutuhkan. Saya tidak dapat mengingat fungsi mana itu, tetapi untuk Visual Studio 2015 Microsoft membuat satu fungsi CRT sebaris. Tiba-tiba itu ada di tajuk bukan perpustakaan CRT sehingga perpustakaan yang diharapkan menemukannya pada waktu tautan tidak lagi bisa melakukannya dan ini menghasilkan kesalahan tautan. Hasilnya adalah perpustakaan ini perlu dikompilasi ulang dengan Visual Studio 2015.

Anda juga bisa mendapatkan kesalahan tautan atau perilaku aneh jika Anda menggunakan API Windows tetapi Anda membangun dengan pengaturan Unicode berbeda untuk pengguna perpustakaan. Ini karena Windows API memiliki fungsi yang menggunakan string Unicode atau ASCII dan makro / definisi yang secara otomatis menggunakan jenis yang benar berdasarkan pengaturan Unicode proyek. Jika Anda meneruskan string melintasi batas pustaka yang jenisnya salah, maka semuanya akan rusak pada waktu proses. Atau Anda mungkin menemukan bahwa program tidak terhubung sejak awal.

Hal-hal ini juga berlaku untuk meneruskan objek / tipe melintasi batas perpustakaan dari perpustakaan pihak ketiga lainnya (misalnya vektor Eigen atau matriks GSL). Jika pustaka pihak ke-3 mengubah tajuknya antara Anda mengompilasi pustaka Anda dan pengguna Anda mengompilasi kode mereka maka semuanya akan rusak.

Pada dasarnya, untuk amannya, satu-satunya hal yang dapat Anda lewati melintasi batas perpustakaan adalah tipe bawaan dan Data Lama Biasa (POD). Idealnya, POD apa pun harus dalam struct yang ditentukan di header Anda sendiri dan tidak bergantung pada header pihak ketiga.

Jika Anda menyediakan pustaka hanya tajuk maka semua kode akan dikompilasi dengan pengaturan kompiler yang sama dan terhadap tajuk yang sama sehingga banyak masalah ini hilang (asalkan versi pustaka ketiga sebagian yang Anda dan pengguna gunakan kompatibel dengan API).

Namun ada hal negatif yang telah disebutkan di atas, seperti bertambahnya waktu kompilasi. Anda juga mungkin menjalankan bisnis, jadi Anda mungkin tidak ingin menyerahkan semua detail penerapan kode sumber kepada semua pengguna Anda jika salah satu dari mereka mencurinya.


8

"Manfaat" utama adalah Anda harus mengirimkan kode sumber, sehingga Anda akan mendapatkan laporan kesalahan pada mesin dan kompiler yang belum pernah Anda dengar. Saat pustaka sepenuhnya berupa templat, Anda tidak punya banyak pilihan, tetapi bila Anda punya pilihan, tajuk saja biasanya merupakan pilihan teknik yang buruk. (Di sisi lain, tentu saja, header hanya berarti Anda tidak perlu mendokumentasikan prosedur integrasi apa pun.)


0

Inlining dapat dilakukan dengan Link Time Optimization (LTO)

Saya ingin menyoroti ini karena ini mengurangi nilai salah satu dari dua keuntungan utama dari perpustakaan hanya header: "Anda perlu definisi pada header untuk sebaris".

Contoh konkret minimal ini ditunjukkan di: Pengoptimalan waktu tautan dan sebaris

Jadi, Anda cukup meneruskan bendera, dan penyebarisan dapat dilakukan di seluruh file objek tanpa pekerjaan pemfaktoran ulang, tidak perlu lagi menyimpan definisi di header untuk itu.

LTO mungkin memiliki kelemahannya sendiri juga: Apakah ada alasan mengapa tidak menggunakan optimasi waktu tautan (LTO)?

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.