Отже, мені цікаво, що ця методика справді використовується на практиці? Чи варто використовувати його скрізь або з обережністю?
Звичайно, використовується. Я використовую це у своєму проекті, майже в кожному класі.
Причини використання ідіоми PIMPL:
Бінарна сумісність
Коли ви розробляєте бібліотеку, ви можете додавати / змінювати поля, XImpl
не порушуючи бінарної сумісності з вашим клієнтом (це може означати збої!). Оскільки двійковий макет X
класу не змінюється, коли ви додаєте нові поля до Ximpl
класу, безпечно додавати нову функціональність у бібліотеку в оновленнях незначних версій.
Звичайно, ви можете також додати нові публічні / приватні невіртуальні методи до X
/ XImpl
без порушення бінарної сумісності, але це нарівні зі стандартною технікою заголовка / реалізації.
Приховування даних
Якщо ви розробляєте бібліотеку, особливо фірмову, може бути бажано не розкривати, які інші бібліотеки / методи реалізації використовувались для реалізації публічного інтерфейсу вашої бібліотеки. Або через проблеми інтелектуальної власності, або через те, що ви вважаєте, що користувачі можуть спокусити зробити небезпечні припущення щодо впровадження або просто порушити інкапсуляцію, використовуючи жахливі прийоми кастингу. PIMPL це вирішує / пом’якшує.
Час компіляції
Час компіляції скорочується, оскільки потрібно лише X
перебудовувати вихідний (імплементаційний) файл, коли ви додаєте / видаляєте поля та / або методи до XImpl
класу (який відображає додавання приватних полів / методів у стандартній техніці). На практиці це звичайна операція.
За допомогою стандартної техніки заголовка / реалізації (без PIMPL), коли ви додаєте нове поле до X
кожного клієнта, який коли-небудь виділяє X
(або в стеці, або в купі), потрібно перекомпілювати, оскільки він повинен регулювати розмір розподілу. Ну, і кожен клієнт, який ніколи не виділяє X, також повинен бути перекомпільований, але це просто накладні витрати (результат коду на стороні клієнта буде однаковим).
Більше того, стандартне розділення заголовка / реалізації XClient1.cpp
потрібно перекомпілювати навіть тоді, коли приватний метод X::foo()
був доданий X
та X.h
змінений, хоча, XClient1.cpp
можливо, не можна викликати цей метод з причини інкапсуляції! Як і вище, вона чиста накладні витрати і пов'язана з тим, як працюють системи побудови C ++ у реальному житті.
Звичайно, рекомпіляція не потрібна, коли ви просто змінюєте реалізацію методів (оскільки ви не торкаєтесь заголовка), але це нарівні зі стандартною технікою заголовка / реалізації.
Чи рекомендується цей прийом використовувати у вбудованих системах (де продуктивність дуже важлива)?
Це залежить від того, наскільки потужна ваша мета. Однак єдина відповідь на це питання: вимірюйте та оцінюйте те, що ви отримуєте та втрачаєте. Також врахуйте, що якщо ви не публікуєте бібліотеку, яку клієнти повинні використовувати у вбудованих системах, застосовується лише перевага часу компіляції!
struct XImpl : public X
. Мені це здається більш природним. Чи є якась інша проблема, яку я пропустив?