Quindi, mi chiedo che questa tecnica sia davvero utilizzata nella pratica? Dovrei usarlo ovunque o con cautela?
Certo che è usato. Lo uso nel mio progetto, in quasi tutte le classi.
Motivi per l'utilizzo del linguaggio PIMPL:
Compatibilità binaria
Quando stai sviluppando una libreria, puoi aggiungere / modificare campi XImplsenza interrompere la compatibilità binaria con il tuo client (il che significherebbe arresti anomali!). Poiché il layout binario della Xclasse non cambia quando si aggiungono nuovi campi alla Ximplclasse, è sicuro aggiungere nuove funzionalità alla libreria negli aggiornamenti delle versioni minori.
Ovviamente, puoi anche aggiungere nuovi metodi non virtuali pubblici / privati a X/ XImplsenza interrompere la compatibilità binaria, ma è alla pari con la tecnica standard di intestazione / implementazione.
Dati nascosti
Se stai sviluppando una libreria, specialmente una proprietaria, potrebbe essere desiderabile non rivelare quali altre librerie / tecniche di implementazione sono state utilizzate per implementare l'interfaccia pubblica della tua libreria. O a causa di problemi di proprietà intellettuale o perché ritieni che gli utenti potrebbero essere tentati di fare ipotesi pericolose sull'implementazione o semplicemente rompere l'incapsulamento usando terribili trucchi di lancio. PIMPL risolve / mitiga questo.
Tempo di compilazione
Il tempo di compilazione è ridotto, poiché è Xnecessario ricostruire solo il file di origine (implementazione) quando si aggiungono / rimuovono campi e / o metodi alla XImplclasse (che associa all'aggiunta di campi / metodi privati nella tecnica standard). In pratica, è un'operazione comune.
Con la tecnica standard di intestazione / implementazione (senza PIMPL), quando si aggiunge un nuovo campo a X, tutti i client che allocano X(sia in stack che in heap) devono essere ricompilati, perché devono regolare le dimensioni dell'allocazione. Bene, ogni cliente che non mai allocare X anche bisogno di essere ricompilato, ma è solo in testa (il codice risultante sul lato client sarà lo stesso).
Inoltre, con la separazione standard di intestazione / implementazione XClient1.cppdeve essere ricompilata anche quando è X::foo()stato aggiunto Xe X.hmodificato un metodo privato , anche se XClient1.cppnon è possibile chiamarlo per motivi di incapsulamento! Come sopra, è puro sovraccarico ed è correlato a come funzionano i sistemi di build C ++ nella vita reale.
Naturalmente, la ricompilazione non è necessaria quando si modifica semplicemente l'implementazione dei metodi (perché non si tocca l'intestazione), ma è alla pari con l'intestazione / tecnica di implementazione standard.
Si consiglia di utilizzare questa tecnica nei sistemi embedded (dove le prestazioni sono molto importanti)?
Dipende da quanto è potente il tuo obiettivo. Tuttavia l'unica risposta a questa domanda è: misurare e valutare ciò che si guadagna e si perde. Inoltre, tieni presente che se non stai pubblicando una libreria destinata ai client per essere utilizzata nei sistemi incorporati, si applica solo il vantaggio del tempo di compilazione!
struct XImpl : public X. Mi sembra più naturale. C'è qualche altro problema che mi sono perso?