Apakah perpustakaan hanya header-lebih efisien?

48

Asumsi

  1. Salah satu keuntungan dari perpustakaan header-only untuk C ++ adalah bahwa mereka tidak perlu dikompilasi secara terpisah.

  2. Dalam C dan C ++ inlinemasuk akal hanya jika fungsi didefinisikan dalam file header *.

  3. Secara tradisional, dalam tata letak C, .c / .h telah digunakan, di mana tajuk mewakili antarmuka publik minimal dari unit terjemahan. Demikian pula, .cpp / hpp.

Pertanyaan

Apakah perpustakaan hanya header umumnya lebih efisien kode-dan waktu pelaksanaan bijaksana daripada tata letak tradisional? Jika demikian, apakah ini karena inlining ekstensif atau optimasi lainnya?

* - mendefinisikan fungsi dalam header memungkinkan kompiler untuk melihat implementasi selama kompilasi dari setiap unit terjemahan dan secara praktis memungkinkan inlining kode

Vorac
sumber
2
Anda akan terkejut betapa baiknya banyak penghubung C ++ modern (GCC, MSVC, ICC, dll) dapat memasukkan kode inline di seluruh unit terjemahan yang terpisah. Saya akan mengatakan "umumnya tidak" pada perspektif efisiensi mengingat berapa kali mengoptimalkan linker menantang harapan saya dan tetap berhasil sejalan (itu tidak termasuk konteks dylib di mana inlining dalam header atau menyediakan implementasi dalam perpustakaan yang terhubung secara statis terpisah dapat membantu) . Namun perpustakaan hanya header, asalkan mereka stabil di kedua antarmuka dan implementasi, bisa menjadi seksi karena betapa mudahnya mereka dapat digunakan dalam proyek-proyek baru.
1
Saya tidak tahu bahwa ini pantas jawaban penuh, tetapi satu manfaat besar dari header hanya lib adalah kemudahan instalasi dan penggunaan: Unduh, #include "lib.h (pp)", selesai.
WeRelic

Jawaban:

44

Salah satu keuntungan dari perpustakaan header-only untuk C ++ adalah bahwa mereka tidak perlu dikompilasi secara terpisah

Tidak, itu bukan keuntungan, justru sebaliknya - bagian utama perpustakaan harus dikompilasi sesering mungkin dimasukkan, bukan hanya sekali. Itu biasanya akan meningkatkan waktu kompilasi. Namun, jika Anda mengacu pada kelebihan yang tercantum di sini di Wikipedia : artikel itu berbicara tentang penurunan biaya administrasi terkait keseluruhan proses pembuatan, pengemasan, dan penyebaran.

Dalam C dan C ++ sebaris masuk akal hanya jika fungsi didefinisikan dalam file header *

Ini tergantung pada sistem compiler / linker, tapi saya kira untuk sebagian besar C dan C ++ compiler ini benar.

Secara tradisional, dalam tata letak C, .c / .h telah digunakan, di mana tajuk mewakili antarmuka publik minimal dari unit terjemahan. Demikian pula, .cpp / hpp.

Itu sebagian besar benar. Header kelas C ++ sering mengandung lebih dari antarmuka publik minimal - mereka biasanya juga mengandung banyak hal pribadi. Untuk mengurangi ini, hal-hal seperti idiom PIMPL digunakan. Ini adalah sesuatu seperti "kebalikan" dari perpustakaan hanya header, ia mencoba untuk meminimalkan konten header yang diperlukan.

Tetapi untuk menjawab pertanyaan utama Anda: ini adalah kompromi. Semakin banyak kode pustaka yang dimasukkan ke file header, semakin banyak kompiler memiliki peluang untuk mengoptimalkan kode untuk kecepatan (jika ini benar-benar terjadi, atau jika peningkatannya terlihat, adalah pertanyaan yang sama sekali berbeda). Di sisi lain, terlalu banyak kode di header meningkatkan waktu kompilasi. Terutama dalam proyek-proyek C ++ besar ini dapat menjadi masalah serius, lihat "Skala Besar C ++ Desain Perangkat Lunak" oleh John Lakos - meskipun buku ini sedikit ketinggalan jaman dan beberapa masalah yang dijelaskan di sana ditangani oleh kompiler modern, ide-ide umum / solusi masih valid.

Khususnya, ketika Anda tidak menggunakan perpustakaan stabil (pihak ketiga), tetapi Anda sedang mengembangkan lib Anda sendiri selama proyek Anda, waktu kompilasi menjadi jelas. Setiap kali Anda mengubah sesuatu di lib, Anda harus mengubah file header, yang akan menyebabkan kompilasi ulang dan keterkaitan semua unit dependen.

IMHO popularitas lib header-saja disebabkan oleh popularitas pemrograman meta template. Untuk kebanyakan kompiler, templated libs harus header-only karena compiler hanya dapat memulai proses kompilasi utama ketika parameter type disediakan, dan untuk kompilasi dan optimisasi penuh kompiler harus melihat "keduanya sekaligus" - kode perpustakaan ditambah templat nilai parameter. Itu membuat tidak mungkin (atau paling tidak sulit) untuk menghasilkan unit kompilasi yang "dikompilasi" untuk perpustakaan seperti itu.

Doc Brown
sumber
6
Jadi singkatnya, perpustakaan hanya header lebih nyaman daripada lebih efisien ; dan karena C ++ tidak memiliki manajer paket standar, ini membantu mendorong adopsi.
Matthieu M.
6
@ MatthieuM: tidak, kode yang dikompilasi memang terkadang lebih efisien, dan untuk templat libs, desain khusus header biasanya bukan masalah kenyamanan. Dan peningkatan waktu kompilasi jelas tidak nyaman.
Doc Brown
Memiliki kode panas di header mungkin memang mengarah ke kode terkompilasi yang lebih efisien, namun ini tidak mengharuskan memiliki semua kode di header dan karena itu independen, IMHO, dari perpustakaan hanya header.
Matthieu M.
1
@ MatthieuM .: itu pasti benar, meskipun demikian saya pikir istilah "lebih nyaman" tidak menggambarkan kasus ini dengan baik.
Doc Brown
3
Saya bekerja pada proyek besar yang tertanam di atas OS yang lebih ramping dan lebih lama untuk majikan saya sebelumnya, dan dalam kasus-kasus itu saya bisa membuktikan betapa sakitnya waktu kompilasi yang lama. Siapa pun yang ketahuan memasukkan terlalu banyak ke file header akan ditangani tanpa ampun.
Fred Thomsen
15

Baiklah, mari kita hancurkan beberapa asumsi Anda:

  1. Salah satu keuntungan dari perpustakaan header-only untuk C ++ adalah bahwa mereka tidak perlu dikompilasi secara terpisah.

Mengompilasi sesuatu secara terpisah berarti berpotensi tidak harus mengkompilasi ulang semuanya jika hanya sebagian yang berubah.
Jadi, kerugian bukannya keuntungan.

  1. Dalam C dan C ++ sebaris masuk akal hanya jika fungsi didefinisikan dalam file header *.

Ya, satu-satunya efek yang inlinetersisa adalah pengecualian pada aturan satu definisi .
Celakalah kamu, jika definisi itu berbeda dalam cara apa pun.

Jadi, jika fungsi internal ke unit kompilasi, tandai static. Itu juga membuat inlining lebih mungkin, karena fungsi harus tersedia untuk menyelaraskannya.
Namun, lihat optimasi tautan-waktu, yang didukung oleh setidaknya MSVC ++, gcc, dan dentang.

  1. Secara tradisional, dalam tata letak C, .c / .h telah digunakan, di mana tajuk mewakili antarmuka publik minimal dari unit terjemahan. Demikian pula, .cpp / hpp.

Ya, hanya menghadirkan antarmuka minimal yang merupakan salah satu tujuan, untuk mencapai stabilitas API dan ABI yang lebih tinggi, dan untuk meminimalkan waktu kompilasi.

Khususnya kelas C ++ tidak benar-benar diarahkan untuk itu, karena semua bit pribadi bocor ke header, seperti halnya yang dilindungi apakah Anda ingin mendapatkan dari itu atau tidak.

PIMPL desain-pola adalah untuk mengurangi detail tersebut.

Bagian di mana memisahkan antarmuka dan implementasi sepenuhnya gagal di C ++ adalah templat.
Panitia mencoba melakukan sesuatu dengan templat yang diekspor , tetapi yang telah ditinggalkan terlalu rumit dan tidak benar-benar berfungsi.

Sekarang, mereka bekerja pada sistem modul yang tepat , meskipun lambat. Itu sangat mengurangi waktu kompilasi, dan juga harus meningkatkan stabilitas API dan ABI dengan mengurangi permukaannya.

Apakah perpustakaan hanya header umumnya lebih efisien kode-dan waktu pelaksanaan bijaksana daripada tata letak tradisional? Jika demikian, apakah ini karena inlining ekstensif atau optimasi lainnya?

Pustaka khusus header dapat lebih efisien dalam ukuran kode dan waktu eksekusi, meskipun itu tergantung pada apakah pustaka dibagi, berapa banyak yang digunakan, dengan cara apa, dan apakah inlining membuktikan kemenangan yang menentukan dalam kasus tertentu.

Dan alasan inlining sangat penting untuk optimasi bukan karena inlining itu sendiri adalah dorongan yang besar, tetapi karena peluang untuk propagasi konstan dan optimasi lebih lanjut terbuka.

Deduplicator
sumber