Domanda

Ho guardato un po ' di codice e ho notato che la convenzione era quello di girare i tipi di puntatore, come

SomeStruct* 

in

typedef SomeStruct* pSomeStruct;

C'è alcun merito a questo?

È stato utile?

Soluzione

Questo può essere appropriata quando il puntatore stesso può essere considerato come una "scatola nera", cioè un pezzo di dati la cui rappresentazione interna dovrebbe essere irrilevante per il codice.

In sostanza, se il codice sarà non dereferenziare il puntatore, e basta passarlo intorno funzioni API (a volte da riferimento), quindi non solo il typedef ridurre il numero di *s nel codice, ma suggerisce anche al programmatore che il puntatore non in realtà dovrebbe essere immischiato.

Questo rende anche più facile cambiare l'API in futuro, in caso di necessità. Per esempio, se si passa ad utilizzare un ID piuttosto che un puntatore (o viceversa) esistente codice non si romperà, perché il puntatore è stato mai dovuto essere dereferenziati in primo luogo.

Altri suggerimenti

Non nella mia esperienza. Nascondere la '*' rende il codice difficile da leggere.

L'unica volta che uso un puntatore all'interno del typedef è quando si tratta di puntatori a funzioni:

typedef void (*SigCatcher(int, void (*)(int)))(int);

typedef void (*SigCatcher)(int);

SigCatcher old = signal(SIGINT, SIG_IGN);

In caso contrario, li trovo più confuso di utile.


La dichiarazione colpito-out è del tipo corretto per un puntatore alla funzione signal(), non di catcher segnale. Potrebbe essere più chiaro (utilizzando il tipo corretto SigCatcher sopra) scrivendo:

 typedef SigCatcher (*SignalFunction)(int, SigCatcher);

In alternativa, per dichiarare la funzione signal():

 extern SigCatcher signal(int, SigCatcher);

Cioè, un SignalFunction è un puntatore ad una funzione che prende due argomenti (un int e un SigCatcher) e restituisce un SigCatcher. E signal() è di per sé una funzione che prende due argomenti (un int e un SigCatcher) e restituisce un SigCatcher.

Questo può aiutare a evitare alcuni errori. Ad esempio, nel seguente codice:

int* pointer1, pointer2;

pointer2 non è un int * , è semplice int . Ma con typedef non è questo succederà:

typedef int* pInt;
pInt pointer1, pointer2;

Sono entrambi int * ora.

La mia risposta è un chiaro "No".

Perché?

Beh, prima di tutto, è semplicemente in cambio di un singolo carattere * per un altro singolo carattere p.Che è zero il guadagno.Questo da solo dovrebbe tenere si fa questo, come si è sempre brutto fare cose extra che inutile.

Secondo, e che è la ragione importante, il * porta il che significa che non è buono per nascondere.Se mi passa qualcosa per una funzione come questa

void foo(SomeType bar);

void baz() {
    SomeType myBar = getSomeType();
    foo(myBar);
}

Non mi aspetto il significato di myBar per essere cambiato per passaggio a foo().Dopo tutto, io sto passando da un valore, così foo() solo vede mai una copia di myBar giusto?Non quando SomeType è un alias per significare un qualche tipo di puntatore!

Questo vale sia per i puntatori C e C++ puntatori intelligenti:Se si nasconde il fatto che essi sono i puntatori agli utenti, si creerà confusione che è del tutto inutile.Quindi, per favore, non alias i puntatori.

(Credo che l'abitudine di typedefing tipi di puntatore è solo un incauto tentativo di nascondere quante stelle che ha come programmatore http://wiki.c2.com/?ThreeStarProgrammer .)

Questa è una questione di stile. Si vede questo tipo di codice molto frequentemente nei file di intestazione di Windows. Anche se essi tendono a preferire la versione caso tutto superiore invece di prefisso con un minuscolo p.

Personalmente evito questo uso di typedef. E 'molto più chiara di avere l'utente esplicitamente dicono di volere un Foo * rispetto PFoo. Typedef di sono più adatti in questi giorni per rendere leggibile STL:)

typedef stl::map<stl::wstring,CAdapt<CComPtr<IFoo>> NameToFooMap;

(come tante risposte) dipende.

In C questo è molto comune, come si sta cercando di nascondere che un oggetto è un puntatore. Si sta cercando di implicare che questo è l'oggetto che tutte le funzioni manipolano (sappiamo che è un puntatore al di sotto, ma rappresenta l'oggetto che si sta manipolando).

MYDB   db = MYDBcreateDB("Plop://djdjdjjdjd");

MYDBDoSomthingWithDB(db,5,6,7);
CallLocalFuc(db); // if db is not a pointer things could be complicated.
MYDBdestroyDB(db);

Sotto MYDB è probabilmente un puntatore ad un oggetto.

In C ++ questo non è più necessario.
Soprattutto perché siamo in grado di passare le cose intorno per riferimento ed i metodi sono incorporati nella dichiarazione della classe.

MyDB   db("Plop://djdjdjjdjd");

db.DoSomthingWithDB(5,6,7);
CallLocalFuc(db);   // This time we can call be reference.
db.destroyDB();     // Or let the destructor handle it.

Typedef viene utilizzato per rendere il codice più leggibile, ma facendo puntatore come typedef aumenta la confusione. Meglio evitare i puntatori typedef.

Discussione spiovente assumendo la lingua di interesse è C. Ramificazioni per C ++ non sono state considerate.

Uso di un un typedef puntatore di una struttura senza tag

La domanda Dimensioni di una struttura che è definito come un puntatore solleva un interessante side-light sull'uso typedef per (struttura ) puntatori.

Si consideri il calcestruzzo senza tag (non opaco) definizione del tipo di struttura:

typedef struct { int field1; double field2; } *Information;

I dettagli dei membri sono completamente tangenziali a questa discussione; tutto ciò che conta è che questo non è un tipo opaco come typedef struct tag *tag; (e non è possibile definire tali tipi opachi attraverso un typedef senza tag).

La questione sollevata è 'come si può trovare la dimensione di quella struttura'?

La risposta breve è 'solo attraverso una variabile del tipo'. Non v'è alcun tag da usare con sizeof(struct tag). Non si può utilmente scrivere sizeof(*Information) , per esempio, e sizeof(Information *) è la dimensione di un puntatore al tipo di puntatore, non la dimensione del tipo di struttura.

In realtà, se si vuole allocare una tale struttura, non è possibile crearne uno se non attraverso l'allocazione dinamica (o tecniche di surrogati che imitano l'allocazione dinamica). Non v'è alcun modo per creare una variabile locale del tipo di struttura i cui puntatori sono chiamati Information, né v'è un modo per creare un ambito di file (globale o static) variabile del tipo di struttura, né v'è un modo per incorporare una tale struttura (al contrario di un puntatore a una tale struttura) in un altro tipo di struttura o unione.

È possibile - necessario - scrivere:

Information info = malloc(sizeof(*info));

A parte il fatto che il puntatore è nascosto nel typedef, questa è una buona pratica - se il tipo di modifiche info, l'assegnazione dimensione rimarrà accurate. Ma in questo caso, è anche l'unico modo per ottenere la dimensione della struttura e per allocare la struttura. E non c'è altro modo per creare un'istanza della struttura.

È nocivi?

Dipende dai vostri obiettivi.

Questo non è un tipo opaco -. I dettagli della struttura devono essere definiti quando il tipo di puntatore è typedef'd

Si tratta di un tipo che può essere utilizzato solo con allocazione dinamica della memoria.

Si tratta di un tipo che non ha nome. Il puntatore al tipo di struttura ha un nome, ma il tipo di struttura in sé non è così.

Se si desidera applicare l'allocazione dinamica, questo sembra essere un modo per farlo.

Nel complesso, però, è più probabile che a causare confusione e angoscia di illuminazione.

Sommario

Si tratta, in generale, una cattiva idea di utilizzare typedef per definire un puntatore a un tipo stucture senza tag.

Se si esegue questa operazione, non sarà possibile creare contenitori STL di pSomeStruct const dal momento che il compilatore legge:

list<const pSomeStruct> structs;

come

list<SomeStruct * const> structs;

, che non è un contenitore STL legale in quanto gli elementi non sono cedibili.

domanda .

No.

Si renderà la vostra vita miserabile momento in cui si miscela con const

typedef foo *fooptr;
const fooptr bar1;
const foo *bar2

Sono bar1 e bar2 lo stesso tipo?

E sì, sto solo citando Guru di Herb Sutter. Molto verità ha fatto lei parla. ;)

- Modifica -

L'aggiunta di link all'articolo citato.

http://www.drdobbs.com/conversationsa-midsummer-nights -madness / 184403835

API Win32 fa con quasi ogni struttura (se non tutti)

POINT => *LPPOINT
WNDCLASSEX => *LPWNDCLASSEX
RECT => *LPRECT
PRINT_INFO_2 => *LPPRINT_INFO_2

E 'bello come è consistente, ma a mio parere non aggiunge alcuna eleganza.

Lo scopo con typedef è quello di nascondere i dettagli di implementazione, ma typedef-zione della proprietà puntatore nasconde troppo e rende il codice più difficile da leggere / capire. Quindi, per favore non farlo.


Se si desidera nascondere i dettagli di implementazione (che spesso è una buona cosa da fare), non nasconde la parte puntatore. Prendete per esempio il prototipo per l'interfaccia standard di FILE:

FILE *fopen(const char *filename, const char *mode);
char *fgets(char *s, int size, FILE *stream);

ritorna qui fopen un puntatore per qualche struttura FILE (che non si conoscono i dettagli di implementazione per). Forse FILE non è un buon esempio perché in questo caso si potrebbe aver lavorato con un certo tipo PFILE che nascondeva il fatto che si tratta di un puntatore.

pFILE fopen(const char *filename, const char *mode);
char *fgets(char *s, int size, pFILE stream);

Tuttavia, che avrebbe funzionato solo perché non hai mai pasticciare con il contenuto che viene puntato direttamente a. Nel momento in cui un po 'di typedef puntatore che voi alcuni luoghi modificare il codice diventa molto difficile da leggere nella mia esperienza.

Qualche tempo fa, avrei risposto "no" a questa domanda. Ora, con l'ascesa di puntatori intelligenti, i puntatori non sono sempre definite con solo una stella '*' più. Quindi non v'è nulla di ovvio di un tipo di essere un puntatore o meno.

Così ora direi: è bene typedef puntatori, finché si è fatto molto chiaro che si tratta di un "tipo di puntatore". Ciò significa che è necessario utilizzare un prefisso / suffisso specifico per esso. No, "p" non è un prefisso sufficiente, per esempio. Probabilmente sarei andare con "PTR".

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