Es una buena idea para typedef punteros?


Miré a través de algún código y noté que la convención era girar tipos de puntero como

SomeStruct* 

Hacia

typedef SomeStruct* pSomeStruct;

¿Hay algún mérito en esto?

Author: Jonathan Leffler, 2009-04-15

13 answers

Esto puede ser apropiado cuando el puntero en sí puede ser considerado como una "caja negra", es decir, una pieza de datos cuya representación interna debe ser irrelevante para el código.

Esencialmente, si su código nunca desreferenciará el puntero, y simplemente lo pasa alrededor de las funciones de la API (a veces por referencia), entonces no solo el typedef reduce el número de *s en su código, sino que también sugiere al programador que el puntero con.

Esto también hace que sea más fácil cambiar la API en el futuro si surge la necesidad, por ejemplo, utilizando un ID en lugar de un puntero (o viceversa). Dado que se suponía que el puntero nunca debía desreferenciarse en primer lugar, el código existente no se romperá.

 90
Author: Artelius,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-15 03:28:56

No en mi experiencia. Ocultar el ' *' hace que el código sea difícil de leer.

 65
Author: sigjuice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-15 03:17:01

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 más confusos que útiles.


La declaración tachada es el tipo correcto para un puntero a la función signal(), no del receptor de señales. Podría hacerse más claro (usando el tipo corregido SigCatcher anterior) escribiendo:
 typedef SigCatcher (*SignalFunction)(int, SigCatcher);

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

 extern SigCatcher signal(int, SigCatcher);

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

 25
Author: Jonathan Leffler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-06 21:17:53

Esto puede ayudarle a evitar algunos errores. Por ejemplo en el siguiente código:

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;

Ambos son int * ahora.

 16
Author: Sad Developer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-15 03:52:14

Esto (como tantas respuestas) depende.

En C esto es muy común ya que estás tratando de disimular que un objeto es un puntero. Está tratando de implicar que este es el objeto que manipulan todas sus funciones (sabemos que es un puntero debajo, pero 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 de MYDB es probablemente un puntero a algún objeto.

En C++ esto ya no es necesario.
Principalmente porque podemos pasar las cosas por referencia y la los métodos se incorporan en la declaración de 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.
 5
Author: Martin York,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-15 04:45:15

Esto es una cuestión de estilo. Usted ve este tipo de código con mucha frecuencia en los archivos de encabezado de Windows. Aunque tienden a preferir la versión en mayúsculas en lugar de prefijar con una minúscula p.

Personalmente evito este uso de typedef. Es mucho más claro que el usuario diga explícitamente que quiere un Foo* que un PFoo. Typedef se adapta mejor en estos días para hacer STL legible :)

typedef stl::map<stl::wstring,CAdapt<CComPtr<IFoo>> NameToFooMap;
 4
Author: JaredPar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-15 03:19:51

Typedef se usa para hacer que el código sea más legible, pero hacer puntero como typedef aumentará la confusión. Es mejor evitar los punteros typedef.

 4
Author: Chand,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-15 03:55:05

Si hace esto, no podrá crear contenedores STL de const pSomeStruct 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.

Ver esta pregunta .

 3
Author: Dan Hook,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:19

Mi respuesta es un claro "No".

¿Por qué?

Bueno, en primer lugar, simplemente cambias un solo carácter * por otro único carácter p. Eso es cero ganancia. Esto solo debe evitar que hagas esto, ya que siempre es malo hacer cosas adicionales que no tienen sentido.

Segundo, 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 que el el significado de myBar debe cambiarse pasándolo a foo(). Después de todo, estoy pasando por el valor, así que foo() solo ve una copia de myBar ¿verdad? ¡No cuando SomeType está alias para significar algún tipo de puntero!

Esto se aplica tanto a los punteros C como a los punteros inteligentes C++: Si oculta el hecho de que son punteros para sus usuarios, creará confusión que es totalmente innecesaria. Así que, por favor, no alias sus punteros.

(Creo que el hábito de typedefing tipos de puntero es solo un error intenta ocultar cuántas estrellas tiene uno como programador http://wiki.c2.com/?ThreeStarProgrammer .)

 3
Author: cmaster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-09 21:40:45

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

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

Es agradable cómo es consistente, pero en mi opinión no agrega ninguna elegancia.

 2
Author: dreamlax,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-15 03:42:21

Hace algún tiempo, habría contestado "no" a esta pregunta. Ahora, con el aumento de los punteros inteligentes, los punteros ya no siempre se definen con una estrella'*'. Así que no hay nada obvio en que un tipo sea un puntero o no.

Así que ahora diría : está bien para los punteros typedef, siempre y cuando se deje muy claro que es un "tipo de puntero". Eso significa que tienes que usar un prefijo/sufijo específicamente para ello. No, " p " no es un prefijo suficiente, por ejemplo. Probablemente diría "rpp".

 1
Author: Benoît,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-15 05:55:29

Discusión lanzada asumiendo que el lenguaje de interés es C. Las ramificaciones para C++ no han sido consideradas.

Usando un tipo puntero a para una estructura sin etiquetar

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

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

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

Los detalles de los miembros son completamente tangencial a esta discusión; todo lo que importa es que este no es un tipo opaco como typedef struct tag *tag; (y no puede definir tales tipos opacos a través de un typedef sin una etiqueta).

La pregunta planteada es " ¿cómo se puede encontrar el tamaño de esa estructura?"

La respuesta corta es 'solo a través de una variable del tipo'. No hay ninguna etiqueta para usar con sizeof(struct tag). No puedes escribir útilmentesizeof(*Information), por ejemplo, y sizeof(Information *) es el tamaño de un puntero al tipo de puntero, no el tamaño de la tipo de estructura.

De hecho, si desea asignar tal estructura, no puede crear una excepto a través de asignación dinámica (o técnicas sustitutivas que imitan la asignación dinámica). No hay manera de crear una variable local del tipo de estructura cuyos punteros se llaman Information, ni hay una manera de crear una variable de ámbito de archivo (global o static) del tipo de estructura, ni hay una manera de incrustar tal estructura (a diferencia de un puntero a tal 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 cambia, 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 asignar la estructura. Y no hay otra manera de crear una instancia de la estructura.

¿Es esto dañino?

Depende de tus objetivos.

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

Es un tipo que solo se puede usar 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 lo tiene.

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

En general, sin embargo, es más probable que cause confusión y angustia que iluminación.

Resumen

Es, en general, una mala idea usar typedef para definir un puntero a un tipo de estructura sin etiquetas.

 1
Author: Jonathan Leffler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:09:59

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


Si desea ocultar los detalles de la implementación (lo que a menudo es algo bueno), no oculte la parte del puntero. Tomemos por ejemplo el prototipo para la interfaz estándar FILE:

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

Aquí fopen devuelve un puntero a alguna estructura FILE (que usted no sabe los detalles de implementación para). Tal vez FILE no es un buen ejemplo porque en este caso podría haber funcionado con algún tipo pFILE que ocultara 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 solo funcionaría porque nunca te metes con el contenido al que se apunta directamente. En el momento en que escribes un puntero que modificas el código se vuelve muy difícil de leer en mi experiencia.

 -1
Author: hlovdal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-15 21:02:51