Pregunta

Revisé algo de código y noté que la convención era convertir tipos de puntero como

SomeStruct* 

en

typedef SomeStruct* pSomeStruct;

¿Hay algún mérito en esto?

¿Fue útil?

Solución

Esto puede ser apropiado cuando el puntero en sí puede considerarse como un "recuadro negro", es decir, una pieza de información cuya representación interna debe ser irrelevante para el código.

En esencia, si su código no eliminar la referencia al puntero, y que acaba de pasar alrededor de funciones de la API (a veces por referencia), entonces no sólo el typedef reducir el número de *s en su código, pero también sugiere que el programador que el puntero no debe realmente se enrede.

Esto también hace que sea más fácil cambiar la API en el futuro si surge la necesidad. Por ejemplo, si cambia a la utilización de una identificación en lugar de un puntero (o viceversa) vigente código no se romperá porque el puntero no se suponía que dejar de hacer referencia, en primer lugar.

Otros consejos

No en mi experiencia. Cómo ocultar la '*' hace que el código sea difícil de leer.

La única vez que uso un puntero dentro del typedef es cuando se trata de punteros a funciones:

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

typedef void (*SigCatcher)(int);

SigCatcher old = signal(SIGINT, SIG_IGN);

De lo contrario, los encuentro confunde más que ayuda.


La declaración tachado es el tipo correcto para un puntero a la función signal(), no del receptor de la señal. Podría ser más clara (utilizando el tipo SigCatcher corregido anteriormente) mediante la escritura:

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

O, para declarar la función signal():

 extern SigCatcher signal(int, SigCatcher);

Es decir, un SignalFunction es un puntero a una función que toma dos argumentos (un int y una SigCatcher) y devuelve un SigCatcher. Y signal() en sí es una función que toma dos argumentos (un int y una SigCatcher) y devuelve un SigCatcher.

Esto puede ayudar a evitar algunos errores. Por ejemplo, en código siguiente:

int* pointer1, pointer2;

pointer2 no es un int * , es simple int . Pero con typedefs esto no va a suceder:

typedef int* pInt;
pInt pointer1, pointer2;

Los dos son int * ahora.

Mi respuesta es un claro "No".

¿Por qué?

Bueno, primero que nada, simplemente intercambias un solo personaje. * por otro solo personaje p.Eso es cero ganar.Esto por sí solo debería impedirte hacer esto, ya que siempre es malo hacer cosas adicionales que no tienen sentido.

En segundo lugar, y esa es la razón importante, el * lleva un significado que no es bueno ocultar.Si paso algo a una función como esta

void foo(SomeType bar);

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

No espero el significado de myBar para cambiar pasándolo a foo().Después de todo, estoy pasando por valor, así que foo() sólo ve una copia de myBar ¿bien?No cuando SomeType ¡Tiene un alias que significa algún tipo de puntero!

Esto se aplica tanto a los punteros C como a los punteros inteligentes C++:Si ocultas el hecho de que son indicadores para tus usuarios, crearás una confusión totalmente innecesaria.Así que, por favor, no pongas un alias en tus punteros.

(Creo que el hábito de definir tipos de punteros es solo un intento equivocado de ocultar cuántas estrellas tiene uno como programador http://wiki.c2.com/?ThreeStarProgrammer .)

Esto es una cuestión de estilo. Usted ve este tipo de código muy frecuentemente en los archivos de encabezado de Windows. Aunque tienden a preferir la versión caso todo superior en lugar de prefijar con una letra minúscula p.

Personalmente evito este uso de typedef. Es mucho más clara para que el usuario explícitamente dicen que quieren un Foo * que PFoo. de typedef se adaptan mejor en estos días para hacer legible STL:)

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

(como tantas respuestas) depende.

En C Esto es muy común que usted está tratando de disimular que un objeto es un puntero. Usted está tratando de dar a entender que este es el objeto de que todas sus funciones manipulan (sabemos que es un puntero debajo, pero que representa el objeto que está manipulando).

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

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

Debajo MYDB es probablemente un puntero en algún objeto.

En C ++ esto ya no es necesario.
Sobre todo porque podemos pasar las cosas por referencia y los métodos se incorporan a la declaración de la clase.

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 se utiliza para hacer el código más legible, pero haciendo que el indicador como typedef aumentará la confusión. Es mejor evitar los punteros typedef.

La discusión se inició asumiendo que el idioma de interés es C.No se han considerado las ramificaciones para C++.

Usando un typedef de puntero para una estructura sin etiquetar

La pregunta Tamaño de una estructura que se define como un puntero. plantea una interesante perspectiva sobre el uso typedef para punteros (estructura).

Considere la definición del tipo de estructura de hormigón sin etiquetas (no opaca):

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

Los detalles de los integrantes son completamente tangenciales a esta discusión;Lo único que importa es que este no sea un tipo opaco como typedef struct tag *tag; (y no se pueden definir tipos tan opacos a través de un typedef sin etiqueta).

La pregunta que surge es '¿cómo puedes encontrar el tamaño de esa estructura'?

La respuesta corta es "sólo mediante una variable del tipo".No hay ninguna etiqueta para usar sizeof(struct tag).No puedes escribir útilmente sizeof(*Information), por ejemplo, y sizeof(Information *) es el tamaño de un puntero al tipo de puntero, no el tamaño del tipo de estructura.

De hecho, si desea asignar dicha estructura, no puede crear una excepto mediante asignación dinámica (o técnicas sustitutas que imiten la asignación dinámica).No hay forma de crear una variable local del tipo de estructura cuyos punteros se llaman Information, ni hay una manera de crear un alcance de archivo (global o static) variable del tipo de estructura, ni hay una manera de incrustar dicha estructura (a diferencia de un puntero a dicha estructura) en otra estructura o tipo de unión.

Puedes (debes) escribir:

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

Aparte del hecho de que el puntero está oculto en el typedef, esta es una buena práctica: si el tipo de info cambios, la asignación de tamaño seguirá siendo precisa.Pero en este caso, también es la única manera de obtener el tamaño de la estructura y asignarla.Y no hay otra forma de crear una instancia de la estructura.

¿Es esto perjudicial?

Depende de tus objetivos.

Este no es un tipo opaco: los detalles de la estructura deben definirse cuando el tipo de puntero es typedef'd.

Es un tipo que sólo se puede utilizar con asignación de memoria dinámica.

Es un tipo que no tiene nombre.El puntero al tipo de estructura tiene un nombre, pero el tipo de estructura en sí no.

Si desea imponer la asignación dinámica, esta parece ser una forma de hacerlo.

Sin embargo, en general, es más probable que cause confusión y angustia que esclarecimiento.

Resumen

En general, es una mala idea utilizar typedef para definir un puntero a un tipo de estructura sin etiquetas.

Si lo hace, usted no será capaz de crear contenedores STL de pSomeStruct const ya que el compilador lee:

list<const pSomeStruct> structs;

como

list<SomeStruct * const> structs;

que no es un contenedor STL legal ya que los elementos no son asignables.

pregunta .

No.

Se le hará la vida imposible en el momento que lo mezcla con const

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

Se bar1 y bar2 del mismo tipo?

Y sí, sólo estoy citando Guru de Herb Sutter. Mucha verdad hizo que hablar. ;)

- Editar -

Adición de enlace a artículo citado.

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

Win32 API hace esto con casi todas las estructuras (si no todos)

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

Es agradable cómo es consistente, pero en mi opinión no se le añade ninguna elegancia.

El propósito con typedef es ocultar los detalles de implementación, pero typedef-ción de la propiedad puntero esconde demasiado y hace que el código sea más difícil de leer / entender. Así que por favor no lo hagas.


Si desea ocultar los detalles de implementación (que a menudo es una buena cosa que hacer), no ocultan la parte puntero. Tomemos, por ejemplo, en el prototipo de la interfaz FILE estándar:

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

Los rendimientos aquí fopen un puntero en cierta FILE estructura (que no conoce los detalles de implementación para). Tal vez FILE no es un buen ejemplo, porque en este caso se podría haber trabajado con algún tipo pfile que ocultaba el hecho de que es un puntero.

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

Sin embargo, eso sólo funcionaría porque nunca perder el tiempo con el contenido al que apunta directamente. En el momento en que algunos typedef puntero que ustedes algunos lugares modificar el código se vuelve muy difícil de leer en mi experiencia.

Hace algún tiempo, me han respondido "no" a esta pregunta. Ahora, con la aparición de punteros inteligentes, los punteros no siempre se definen con una estrella '*' más. Así que no hay nada obvio sobre un tipo de ser un puntero o no.

Así que ahora yo diría: está bien para typedef punteros, con tal de que se hace muy claro que se trata de un "tipo de puntero". Eso significa que usted tiene que usar un prefijo / sufijo específicamente para él. No, "p" no es un prefijo suficiente, por ejemplo. Probablemente me voy con "ptr".

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top