Domanda

In un sacco di C ++ API (COM-based quelli in mente) che make qualcosa per te, il puntatore all'oggetto che è costruito è di solito richiesto come un puntatore ** (e la funzione costruirà e init per voi)

di solito si vede firme come:

HRESULT createAnObject( int howbig, Object **objectYouWantMeToInitialize ) ;

-., Ma si vede raramente il nuovo oggetto viene passato come valore di ritorno

Oltre a persone che vogliono vedere i codici di errore, qual è la ragione di questo? E 'meglio utilizzare il modello ** piuttosto che un puntatore restituito per le operazioni più semplici come ad esempio:

wchar_t* getUnicode( const char* src ) ;

O sarebbe meglio questo essere scritto come:

void getUnicode( const char* src, wchar_t** dst ) ;

La cosa più importante che posso pensare è quello di ricordarsi di liberarlo, e il modo in **, per qualche ragione, tende a ricordarmi che devo rilasciare esso pure.

È stato utile?

Soluzione

"Oltre a volere i codici di errore"?

Cosa ti fa pensare che ci è un oltre. I codici di errore sono praticamente la sola e unica ragione. La funzione ha bisogno di qualche modo per indicare il fallimento. C non ha eccezioni, quindi ha a che fare, che sia attraverso un parametro puntatore, o il valore di ritorno, e il valore di ritorno è idiomatico, e più facile da controllare quando si chiama la funzione.

(A proposito, non c'è una regola universale che mezzi ** si deve liberare l'oggetto. Questo non è sempre il caso, ed è probabilmente una cattiva idea di usare qualcosa che arbitrario per ricordare gli oggetti da pulire.)

Altri suggerimenti

Due ragioni mi vengono in mente.

In primo luogo sono i codici di errore in realtà. Altro che C ++, C non ha eccezioni, e COM è un C-API. Anche molti progetti C ++ basato preferiscono non utilizzare le eccezioni per vari motivi. Ci possono essere casi in cui un valore di ritorno non può segnalare gli errori, ad esempio se la funzione restituisce un intero, non ci può essere valore intero, che può rappresentare un codice di errore. Mentre segnalazione errori con i puntatori è facile (NULL == Errore), alcuni progettisti API preferiscono errori di segnale in modo coerente di tutte le funzioni.

In secondo luogo, le funzioni può avere solo un valore di ritorno, ma chiamandoli può creare più oggetti. Alcune funzioni API Win32 prendono più puntatori ai puntatori che possono essere riempiti opzionalmente, se si chiama queste funzioni con puntatori non NULL. Non è possibile tornare due puntatori, o meglio questo sarebbe scomodi da usare, se il valore di ritorno è un po 'struct per valore che contiene più di un puntatore. Anche qui un'API consistente è un obiettivo ragionevole da raggiungere.

I nuovi oggetti in argomenti della funzione passati da ** è meglio. Questo mi prendere un conforto per l'uso futuro del cambiamento void per bool per esempio al successo ritorno di una funzione o di altre informazioni che fornisce lavori di funzione.

risposta in una sola riga:. Questo è molto meglio per i codici di errore risultante

  

Oltre a persone che vogliono vedere i codici di errore, qual è la ragione di questo?

Ci sono alcune ragioni per questo. Uno di loro sta scrivendo un'interfaccia che è utilizzabile in C (si vede questo nel WinAPI e Windows COM).

compatibilità all'indietro è un altro motivo (vale a dire l'interfaccia è stato scritto in quel modo e la rottura ora si spezzerebbe il codice esistente).

mi piacerebbe andare con compatibilità C per un principio di progettazione quando si utilizza il codice come questo. Se si dovesse scrivere in C ++ devi scrivere

retval Myfunction(Result *& output);

anziché

retval Myfunction(Result ** output);

o (ancora meglio):

Result *Myfunction();

e hanno la funzione di un'eccezione in caso di errore.

Non sono sicuro Sono d'accordo che è il modo migliore per farlo ... questo potrebbe essere migliore:

Object * createAnObject(int howbig, HRESULT * optPlaceResultCodeHereIfNotNull = NULL);

In questo modo non c'è Giochi per bambini con doppio indirezione (che può essere un po 'difficile per le persone che non sono abituati ad esso), e le persone che non si preoccupano di codici risultato non c'è bisogno di preoccuparsi circa il secondo argomento a tutti ... si può solo verificare se il valore di ritorno è NULL o meno.

In realtà, dal momento che è C ++, si potrebbe rendere le cose ancora più facile, usando la funzione sovraccarico:

Object * createAnObject(int howbig);
Object * createAnObject(int howbig, HRESULT & returnResultCode);

Ogni chiamata di metodo in una chiamata COM deve essere HRESULT. I codici di ritorno vengono sfruttate in tutto il quadro e passando un doppio puntatore è un modo noto per ottenere l'oggetto creato.

Non rispondere alla tua domanda, ma un commento come tua domanda ha fatto uscire alcuni pensieri che ho su COM / DCOM di programmazione in C ++.

Tutte queste "puntatore" e "puntatore a puntatore", la gestione della memoria e il conteggio di riferimento sono le ragioni per cui ho rifuggire dal fare la programmazione COM con C ++. Anche con ATL a posto, non mi piace per la semplice ragione che non sembra abbastanza naturale. Detto questo, ho fatto fare un paio di progetti che utilizzano ATL.

A quel tempo l'alternativa è l'uso di VB. sguardi codice VB più naturali per COM o la programmazione DCOM.

Oggi, vorrei utilizzare C #.

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