Domanda

Abbiamo una libreria C ++ che forniamo a diversi client. Di recente abbiamo fatto il passaggio dall'uso di puntatori non elaborati nell'interfaccia pubblica all'utilizzo di boost :: sharedptr. Ciò ha fornito un enorme vantaggio, come puoi immaginare, in quanto ora i clienti non devono più preoccuparsi di chi deve eliminare cosa e quando. Quando abbiamo fatto il passaggio, ho pensato che fosse la cosa giusta da fare, ma mi dava fastidio dover includere qualcosa da una libreria di terze parti nella nostra interfaccia pubblica - in genere eviti quel genere di cose se puoi. Ho razionalizzato il fatto che il boost fosse praticamente parte del linguaggio C ++ ora, e il nostro caso d'uso richiede che sia il codice client che la libreria mantengano puntatori agli oggetti. Tuttavia, recentemente uno dei nostri clienti ci ha chiesto se potevamo passare a utilizzare una classe di puntatori intelligenti neutri nell'interfaccia, perché la nostra libreria li sta essenzialmente costringendo a una particolare versione di boost, un punto che certamente comprendo e apprezzo. Quindi ora mi chiedo quale potrebbe essere il miglior modo di agire. Ci ho pensato un po ', e mi chiedevo come creare una semplice classe di puntatori intelligenti che contenesse semplicemente un vero puntatore intelligente di boost. Ma poi i clienti probabilmente inseriranno immediatamente uno di quelli nel loro sapore di boost :: sharedptr, e poi saremmo tre puntatori condivisi in profondità - il che potrebbe essere un problema, oppure no. Ad ogni modo, mi piacerebbe sentire alcune opinioni della community sul modo migliore per risolvere questo problema.

Modifica: originariamente avevo detto trasferimento di proprietà, ma avrei dovuto specificare che il codice su entrambi i lati del limite API deve contenere un puntatore all'oggetto.

È stato utile?

Soluzione

shared_ptr lt &; & Gt; è parte della lingua, a partire dal rilascio di TR1. Vedi: (TR1)

Altri suggerimenti

Una possibile soluzione è spedire boost :: shared_ptr con il tuo progetto. Essendo tutto composto da intestazioni, ciò libererebbe i tuoi clienti dal dover installare manualmente le librerie boost. Puoi utilizzare bcp per ottenere tutti i file necessari a un particolare libreria boost, comprese le librerie stesse. L'ho fatto quando all'epoca lavoravo per un'azienda e avevo bisogno di boost::shared_ptr e in realtà ha funzionato molto.

Se la semantica è veramente trasferimento di proprietà , perché non usare auto_ptr poiché è C ++ standard? Internamente, puoi ancora costruire i tuoi shared_ptr da auto_ptr e quindi avere la proprietà condivisa se ne hai bisogno.

Prima di tutto, se distribuisci la tua libreria come codice sorgente anziché come libreria compilata, puoi ignorare questa risposta. Ci sono anche alcuni problemi specifici di Windows che potrebbero non essere rilevanti per altre piattaforme.

Personalmente penso che dovresti evitare di avere troppo c ++ funky nell'interfaccia pubblica della tua libreria poiché può causare molti problemi al client.

Non sono sicuro di quanto sia applicabile al tuo esempio particolare, ma ho riscontrato personalmente problemi in cui i simboli della libreria stl che ho usato erano in conflitto con quelli nella libreria di terze parti quando sono passato a una nuova versione. Ciò significa che abbiamo avuto incidenti in posti strani e ho dovuto fare molti trucchi per evitare il problema. Alla fine sono rimasto con la vecchia versione della libreria per questo.

Un altro problema che si può incontrare è che diversi compilatori c ++ possono manipolare gli stessi simboli in modo diverso, il che significa che potenzialmente è necessario fornire una libreria separata per ogni compilatore che si desidera supportare anche se usano la stessa versione di Boost. Dai un'occhiata al libro & Quot; Imperfect C ++ & Quot; per una discussione al riguardo.

Nell'attuale mondo di diversi compilatori e ambienti C ++ penso che la triste verità sia che dovresti evitare di avere qualsiasi cosa tranne C nell'interfaccia e assicurarti di collegare dinamicamente la tua biblioteca (per evitare conflitti quando colleghi i tuoi clienti collega la tua biblioteca, la libreria di runtime di Windows può essere una vera seccatura qui). Puoi ancora usare boost e tutto il c ++ di fantasia all'interno della tua libreria che vuoi poiché tutti i tuoi simboli saranno isolati dall'ambiente dei tuoi clienti nella dll.

Se vuoi davvero avere puntatori intelligenti e altre belle funzionalità C ++ nell'interfaccia della tua libreria, crea un comodo livello per il quale distribuisci il codice sorgente. Questo farà in modo che sia sempre compilato nell'ambiente dei clienti. Questa interfaccia chiama quindi le funzioni C esposte in modi intelligenti. Non penso sia una buona idea usare la spinta in quel livello perché costringerà i tuoi clienti ad adottarlo anche se non lo desiderano, tuttavia è facile sostituirlo o trovare un'altra soluzione poiché quel livello è distribuito come sorgente codice.

Un'altra caratteristica interessante è che in genere è più facile chiamare funzioni C in una DLL rispetto alle funzioni c ++ con uno strano nome mangling se si desidera esporre la propria libreria in lingue diverse da C / C ++.

Questo approccio rende sicuramente la tua vita più complicata in molti modi, ma è un modo per rendere meno probabile che le persone evitino la tua biblioteca perché non era possibile collegarsi con successo con il proprio codice.

Questo è C ++. Sai, potresti modellare la classe dell'interfaccia sull'implementazione del puntatore condiviso.

Questa è una domanda interessante che ho da tempo. Forzate i vostri utenti in qualsiasi libreria fornite o lasciate che decidano su cosa è meglio nel loro progetto? Come sempre, la domanda è: cosa stai offrendo e cosa stai chiedendo all'utente.

Se usi i puntatori non elaborati, consenti ogni tipo di possibilità. Il codice utente può utilizzare un puntatore non elaborato, memorizzarlo in std :: auto_ptr, shared_ptr (sia boost o TR1) o nella versione homebrewed di un puntatore smart. Ma ciò potrebbe anche mettere in difficoltà l'utente se dimentica di rilasciare la memoria e richiede un po 'più di codice nel suo lato se desidera solo un temporaneo creato per una chiamata di metodo (se si forniscono puntatori non elaborati, dovranno archiviare il puntatore in una variabile puntatore [possibilmente intelligente] non temporanea).

Ora, se si utilizza un puntatore intelligente, si sta forzando la soluzione nell'utente. Se intendono utilizzare la propria versione di un puntatore intelligente (supponiamo che tu usi boost :: shared_ptr e vogliono std :: tr1 :: shared_ptr) non possono più usarlo se funzionano con la tua interfaccia. Qualunque sia il puntatore intelligente su cui decidi (oltre a std :: auto_ptr che è speciale) non stai solo forzando una soluzione, ma anche i problemi che ha.

Se l'utente ha un'applicazione multithread e la soluzione non è thread-safe, l'utente è vincolato a una soluzione non sicura. Se, d'altra parte, il puntatore intelligente è thread-safe ma comporta costi di blocco, tali costi vengono trasferiti agli utenti anche se funzionano in un'applicazione multithread. Se compili la tua libreria (non solo un'intestazione lib), stai forzando non solo un tipo di puntatore intelligente, ma anche una versione particolare di esso, poiché qualsiasi modifica nella libreria di puntatori intelligenti interromperà la compatibilità del tuo codice.

Come nota a margine, boost :: shared_ptr (boost 1.33+) è thread safe nella maggior parte dei casi e utilizza un'implementazione senza blocco in molte piattaforme. Comunque questo dovrebbe darti un'idea delle cose che dovresti considerare.

Infine, devi considerare che non stai solo vincolando l'utente all'uso del tuo tipo di puntatore intelligente, ma anche la stessa versione di esso. Se compili la tua lib con una particolare versione di boost, l'utente è tenuto a quella particolare implementazione o

È possibile utilizzare l'utilità boost copy per creare una versione personalizzata di boost che avesse solo la classe di puntatore intelligente. Poiché la classe del puntatore intelligente è una libreria di sola intestazione, ciò dovrebbe comportare alcune intestazioni che potresti includere nella tua libreria.

l'introduzione di boost :: shared_ptr impone al tuo client di usare boost. per alcune persone, questo è un problema minore.

forza anche i tuoi client a usare lo stesso compilatore usato dalla tua lib, se la tua lib è distribuita come binaria compilata. oppure, se la tua libreria è distribuita nel codice sorgente, i client devono attenersi alla propria scelta del compilatore usato per compilare la tua lib. questo non è un problema minore per qualsiasi progetto di dimensioni considerevoli.

Utilizzare auto_ptr o attenersi a un'interfaccia C. Forzare le librerie C ++ nella tua interfaccia è sempre brutto, uccide ogni possibilità di essere multipiattaforma e provoca un incubo di manutenzione per i clienti con quotazioni & Diverse; downstream &; configurazioni.

Non appena C ++ 0x è abbastanza mainstream per i tuoi clienti, passa a std::shared_ptr.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top