¿Es una buena idea escribir punteros de definición?

10 minutos de lectura

¿Es una buena idea escribir punteros de definicion
Desconocido

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

SomeStruct* 

dentro

typedef SomeStruct* pSomeStruct;

¿Hay algún mérito en esto?

  • Es común en C. Porque estás tratando de ocultar el hecho de que es un puntero. Este es el objeto que pasa a todas las interfaces en una biblioteca. En C++ no es común y desaconsejado, aunque no desconocido.

    – Martín York

    15 de abril de 2009 a las 4:37

  • Un artículo interesante sobre este tema general: Conversaciones: La locura de una noche de verano Ver también Estilo de codificación del kernel de Linux para una vista extrema de ‘no tipear punteros (y no proporcionar typedefs para estructuras o uniones)’.

    –Jonathan Leffler

    15 de enero de 2019 a las 5:49

  • @MartinYork Uno podría agregar que no es necesario en C ++, ya que tiene soporte para pasar por referencia

    – klutt

    11 de mayo de 2021 a las 9:16

  • @klutt En C ++, usa métodos en lugar de funciones de todos modos, por lo que el objeto oculto (esto) siempre está ahí.

    – Martín York

    11 de mayo de 2021 a las 16:06

1647645252 797 ¿Es una buena idea escribir punteros de definicion
Artelio

Esto puede ser apropiado cuando el propio puntero se puede considerar como una “caja negra”, es decir, un dato cuya representación interna debería ser irrelevante para el código.

Esencialmente, si su código Nunca elimina la referencia del puntero, y simplemente lo pasa por las funciones API (a veces por referencia), entonces el typedef no solo reduce la cantidad de *s en su código, pero también le sugiere al programador que no se debe entrometerse con el puntero.

Esto también facilita cambiar la API en el futuro si surge la necesidad. Por ejemplo, si cambia a usar una ID en lugar de un puntero (o viceversa), el código existente no se romperá porque, en primer lugar, nunca se supuso que el puntero fuera desreferenciado.

  • Ejemplo del mundo real: en OS X, el marco CoreFoundation hace un uso extensivo de esta técnica, refiriéndose a ellos como tipos de datos “opacos”.

    – hbw

    15 de abril de 2009 a las 3:32

  • También en OS X: pthread_t es un tipo opaco; está definido para que sea un puntero a una ‘struct _opaque_pthread_t’, que en sí misma es una matriz opaca de bytes.

    – Adam Rosenfield

    15 de abril de 2009 a las 4:42

  • Contador de ejemplo: ARCHIVO *fp? En realidad, estoy de acuerdo contigo, pero hay un amplio precedente de lo contrario.

    –Jonathan Leffler

    15 de abril de 2009 a las 4:56

  • Por supuesto, si hace esto, no nombra el tipo opaco “pFoo”.

    – MSalters

    15 de abril de 2009 a las 8:59

  • @MattJoiner: la razón FILE* no fue typedef’d como un puntero opaco es para permitir macros como getc() y putc() para manipular la estructura del ARCHIVO directamente y evitar la sobrecarga de la llamada a la función en la mayoría de los casos.

    – chqrlie

    18 de agosto de 2016 a las 8:37

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

  • No sé sobre eso. Quiero decir, si tienes un puntero para decir Device y tu typedef a Device_Ptr (en lugar de tener que usar Device *) o similar es bastante legible. Veo muchas bibliotecas bien maduras y bastante grandes que hacen eso. Especialmente en C ++, si agrega plantillas, esto puede ahorrarle a sus dedos la escritura.

    – rbaleksandar

    15 de febrero de 2017 a las 12:49

  • @rbaleksandar nuevamente, está bien si Device* es un identificador opaco.

    – Alex D.

    06/04/2018 a las 20:18

  • Como C n00b, creo que la sintaxis del puntero de C es una abominación: solo les gusta a aquellas almas desafortunadas que ya pasaron más de 10 años aprendiendo a que les guste. Yo tomaría myTypePtr o myTypeRef sobre esa estrella cualquier día. :PAGS

    – Christoffer Bubach

    30 de junio de 2020 a las 0:37

1647645252 53 ¿Es una buena idea escribir punteros de definicion
jonathan leffler

La única vez que uso un puntero dentro del typedef es cuando trato con 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 signal() función, no del receptor de señal. Se podría hacer más claro (usando el corregido SigCatcher tipo arriba) escribiendo:

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

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

 extern SigCatcher signal(int, SigCatcher);

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

  • ¿Funciona este typedef con menos puntuación? “typedef vacío SigCatcher (int, vacío

    (int) (int)”

    – jugo de sig

  • 18 de abril de 2009 a las 0:13

    No; gcc dice “error: SigCatcher declarado como función que devuelve una función”.

    –Jonathan Leffler

  • 18 de abril de 2009 a las 4:44 Acabo de encontrarme con una declaración de señal definida por tipo aún más simple ()

    freebsd.org/cgi/man.cgi?query=signal

    – jugo de sig

  • 6 de noviembre de 2010 a las 20:17 sig_t @Sigjuice: incluso sin ir a la página de BSD (que no hice hasta después de editar el material), vi grandes problemas con mi respuesta, que ahora están solucionados. Y lo que llama BSD SigCatchercoincide con mi signal() y sí, simplifica la declaración de

    enormemente.

    –Jonathan Leffler

  • 6 de noviembre de 2010 a las 21:20

    frio. La declaración equivalente con el explícito * no se ve tan mal, en mi humilde opinión. typedef void SigCatcher(int); SigCatcher externo *señal(int, SigCatcher *);

    – jugo de sig

6 de noviembre de 2010 a las 22:20

int* pointer1, pointer2;

Esto puede ayudarte a evitar algunos errores. Por ejemplo en el siguiente código: pointer2 no es unEn t * Es simpleEn t

typedef int* pInt;
pInt pointer1, pointer2;

. Pero con typedefs esto no va a pasar: Ellos dos En t *

1647645253 779 ¿Es una buena idea escribir punteros de definicion
ahora.

cmaster – reincorporar a monica

Mi respuesta es un claro “No”.

¿Por qué? * Bueno, antes que nada, simplemente intercambias un solo carácter ppor otro solo personaje . Es decir cero

ganar. Esto solo debería evitar que hagas esto, ya que siempre es malo hacer cosas adicionales que no tienen sentido. En segundo lugar, y esa es la razón importante, * loslleva un significado que no es bueno ocultar

void foo(SomeType bar);

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

. Si le paso algo a una función como esta myBar No espero el significado de foo()para ser cambiado pasándolo a foo() . Después de todo, estoy pasando por valor, así que myBar solo ve una copia de SomeType ¿Correcto? No cuando

tiene un alias para significar algún tipo de puntero! Especialmente cuando ese puntero actúa como una referencia a algún tipo de objeto cuyo valor es básicamente el significado del puntero: no me importará que el puntero en sí no cambie (debido al paso por valor), estoy interesado en si el objeto cambia o no (el objeto detrás del puntero).

Esto se aplica tanto a los punteros de C como a los punteros inteligentes de C++: si oculta el hecho de que son punteros a sus usuarios, creará una confusión totalmente innecesaria. Entonces, por favor, no alias sus 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

  • .) void *vp=/*...*/; foo(vp); +1. Otra razón es que no habrá protección del sistema de tipos contra foo(0);o

    . (Typedefs para enumeraciones y typedefs numéricos para cosas que nunca deberían aparecer como números tienen problemas similares).

    – PSkocik


  • 10 de noviembre de 2018 a las 21:06 Incluso si pasas el puntero myBar a una función, el puntero todavía se está copiando, incluso si los datos a los que apunta no lo están. Entonces el valor myBar de foo(que es una dirección) todavía no se puede cambiar por pero el valor señaló a myBar por

    lata.

    – Aposhiano

  • 11 de agosto de 2021 a las 15:21 struct _fraction @Aposhian Sí. ¿Entonces? – Mi punto es que un puntero generalmente sirve como proxy para algún objeto en la memoria. La semántica del puntero es más o menos la semántica del objeto detrás de él, y cualquier función que reciba el puntero puede cambiarlas. Por ejemplo, si tuviera un tipo Fractiony tipeó su puntero a Fraction a = fraction(84, 2); printFrac(a); doSomething(a); printFrac(a); Las declaraciones Fraction* a = fraction(84, 2); podría producir resultados confusos. Con doSomething(a) está claro que a puede cambiar el significado de

    cambiando el objeto.

    – cmaster – reincorporar a monica

  • 11 de agosto de 2021 a las 15:40 Sí, tiene usted razón. Y estoy de acuerdo en que los punteros typedef-ing son generalmente una ofuscación. Simplemente no quiero que nadie que lea esto confunda el significado/semántica de un puntero y suvalor

    , que son separados y distintos. Recordar esa diferencia es fundamental al reasignar variables de puntero o usar punteros a punteros.

    – Aposhiano


  • 11/08/2021 a las 20:01

    @Aposhian Ah, ahora veo. Bueno, he agregado algunas palabras en el punto en cuestión con la esperanza de aclarar mi significado. Gracias por señalar eso.

    – cmaster – reincorporar a monica

¿Es una buena idea escribir punteros de definicion
11 de agosto de 2021 a las 20:18

jaredpar

Esta es una cuestión de estilo. Este tipo de código se ve con mucha frecuencia en los archivos de encabezado de Windows. Aunque tienden a preferir la versión en mayúsculas en lugar del prefijo con una p minúscula.

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

  • Personalmente, evito este uso de typedef. Es mucho más claro que el usuario diga explícitamente que quiere un Foo* que un PFoo. Los Typedef son los más adecuados en estos días para hacer que STL sea legible 🙂 void *vp=/*...*/; foo(vp); +1. Otra razón es que no habrá protección del sistema de tipos contra foo(0);o

    . (Typedefs para enumeraciones y typedefs numéricos para cosas que nunca deberían aparecer como números tienen problemas similares).

    – PSkocik


  • 10 de noviembre de 2018 a las 21:06 Incluso si pasas el puntero myBar a una función, el puntero todavía se está copiando, incluso si los datos a los que apunta no lo están. Entonces el valor myBar de foo(que es una dirección) todavía no se puede cambiar por pero el valor señaló a myBar por

    lata.

    – Aposhiano

  • 11 de agosto de 2021 a las 15:21 struct _fraction @Aposhian Sí. ¿Entonces? – Mi punto es que un puntero generalmente sirve como proxy para algún objeto en la memoria. La semántica del puntero es más o menos la semántica del objeto detrás de él, y cualquier función que reciba el puntero puede cambiarlas. Por ejemplo, si tuviera un tipo Fractiony tipeó su puntero a Fraction a = fraction(84, 2); printFrac(a); doSomething(a); printFrac(a); Las declaraciones Fraction* a = fraction(84, 2); podría producir resultados confusos. Con doSomething(a) está claro que a puede cambiar el significado de

    cambiando el objeto.

    – cmaster – reincorporar a monica

  • 11 de agosto de 2021 a las 15:40 Sí, tiene usted razón. Y estoy de acuerdo en que los punteros typedef-ing son generalmente una ofuscación. Simplemente no quiero que nadie que lea esto confunda el significado/semántica de un puntero y suvalor

    , que son separados y distintos. Recordar esa diferencia es fundamental al reasignar variables de puntero o usar punteros a punteros.

    – Aposhiano


  • 11/08/2021 a las 20:01

    @Aposhian Ah, ahora veo. Bueno, he agregado algunas palabras en el punto en cuestión con la esperanza de aclarar mi significado. Gracias por señalar eso.

    – cmaster – reincorporar a monica

1647645254 490 ¿Es una buena idea escribir punteros de definicion
11 de agosto de 2021 a las 20:18

martín york

Depende (como tantas respuestas).

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

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

En C, esto es muy común ya que intenta disfrazar 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).

Debajo de MYDB probablemente haya un puntero a algún objeto.
En C++ esto ya no es necesario.

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.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad