¿Es una buena idea "# definirme (* esto)"?

19

Esta macro se puede definir en algún encabezado global, o mejor, como un parámetro de línea de comando del compilador:

#define me (*this)

Y algún ejemplo de uso:

some_header.h:

inline void Update()
{
    /* ... */
}

main.cpp:

#include "some_header.h"

class A {
public:
    void SetX(int x)
    {
        me.x = x;   
        me.Update(); 
    }

    void SomeOtherFunction()
    {
        ::Update();
    }

    /*
        100 or more lines
        ... 
    */

    void Update()
    {
        // ... 
    }

    int x;  
};

Entonces, en un método de clase cuando accedo a un miembro de la clase, siempre estoy usando me, y cuando accedo a un identificador global que siempre uso ::. Esto le da al lector que no está familiarizado con el código (probablemente yo mismo después de unos meses) información localizada de lo que se accede sin la necesidad de buscar en otro lado. Quiero definirlo meporque encuentro que usarlo en this->todas partes es demasiado ruidoso y feo. ¿Pero puede #define me (*this)considerarse una buena práctica de C ++? ¿Hay algunos puntos problemáticos prácticos con la memacro? Y si usted como programador de C ++ será el lector de algún código utilizando la memacro, ¿le gustaría o no?

Editar: Debido a que muchas personas argumentan no específicamente contra el uso me, pero generalmente contra explícito esto. Creo que puede no estar claro cuáles son los beneficios de "explícito esto en todas partes".

¿Cuáles son los beneficios de "explícito esto en todas partes"?

  • Como lector del código, tiene la certeza de a qué se accede y puede concentrarse en diferentes cosas que verificar, en algún código distante, que realmente se accede a lo que cree que se accede.
  • Puede usar la función de búsqueda más específicamente. La búsqueda " this->x" puede proporcionarle más resultados deseados que solo la búsqueda " x"
  • Cuando elimina o cambia el nombre de algún miembro, el compilador le notifica de manera confiable en los lugares donde se usa este miembro. (Algunas funciones globales pueden tener el mismo nombre y existe la posibilidad de que pueda introducir un error si no está usando esto explícitamente).
  • Cuando refactoriza el código y hace explícita la función no miembro del miembro (para hacer una mejor encapsulación), esto le muestra el lugar que debe editar y puede reemplazarlo fácilmente con el puntero a la instancia de la clase dada como parámetro de función no miembro
  • En general, cuando está cambiando el código, hay más posibilidades de errores cuando no está usando esto explícito que cuando está usando esto explícito en todas partes.
  • Explícito, esto es menos ruidoso que "m_" explícito cuando está accediendo al miembro desde afuera ( object.membervs object.m_member) (gracias a @Kaz por detectar este punto)
  • Explícitamente, esto resuelve el problema universalmente para todos los miembros: atributos y métodos, mientras que "m_" u otro prefijo se puede usar prácticamente solo para atributos.

Me gustaría pulir y ampliar esta lista, dígame si conoce otras ventajas y use casos para explícito esto en todas partes .

user3123061
fuente
3
Debe evitar tener argumentos de función y miembros con el mismo nombre, así como evitar "esto" explícito.
pjc50
44
Me recuerda el código VB de mi jefe. Yo Yo Yo en todas partes. Suena egoísta. : p De todos modos, las respuestas hasta ahora lo dicen todo.
MetalMikester
19
¡Es una idea maravillosa! Y para aquellos que provienen de Python, ¿por qué no #define self (*this)? Incluso puede mezclar ambas macros y tener algunos archivos que imitan VB y otros Python. :)
logc
11
¿Por qué no sólo tiene que ir a por todas, y hacer: #include "vb.h", #Include pascal.ho #include FOTRAN.hy tienen la siguiente persona que tocar el código de someterlo a TDWTF .
Dan Neely
44
Oh por favor, solo no. Podrías ahorrarte algunos problemas simplemente declarando atributos como me_x.
Gort the Robot

Respuestas:

90

No, no es.

Tenga en cuenta al programador que mantendrá su código dentro de varios años, mucho después de que se haya ido a pastos más verdes y siga las convenciones comunes del lenguaje que usa. En C ++, casi nunca tiene que escribir this, porque la clase se incluye en el orden de resolución de símbolos y cuando un símbolo se encuentra en el alcance de la clase, this->está implícito. Así que no lo escribas como todos lo hacen.

Si a menudo se confunde qué símbolos provienen del alcance de la clase, el enfoque habitual es usar un patrón de nomenclatura común para los miembros (campos y, a veces, métodos privados; no lo he visto utilizado para métodos públicos). Los comunes incluyen sufijos _o prefijos con m_o m.

Jan Hudec
fuente
12
"En C ++, casi nunca tienes que escribir esto", es una convención totalmente ajena a la pregunta. Algunas personas (como yo) prefieren escribir thispara dejar explícitamente en claro que la variable no es local para el método. La pregunta aquí es si la macro medebería existir, no si thises algo que debería usarse.
Mehrdad
8
@Mehrdad: Porque el OP dice explícitamente que está usando en me.lugar de this->. Como no hay necesidad de this->eso, no hay necesidad de me.hacerlo y, por lo tanto, no hay necesidad de macro.
Martin York
11
@LokiAstari: Nada en la pregunta sugiere remotamente al OP preguntándose si this->"es necesario". De hecho, el OP dice que está usando this->a pesar de que no es necesario. La pregunta es acerca de si me.debe usarse en lugar de this-> , lo que esta respuesta en realidad no responde.
Mehrdad
44
@Mehrdad: Pero solo decir sí o no es una respuesta muy aburrida. Por lo tanto, las explicaciones suelen ser bastante útiles para explicar cómo se alcanza la respuesta (está codificada por Cómo responder ). La conclusión es no usar porque el OP tiene una actitud equivocada para comenzar con el uso thisy, por lo tanto, se requiere una discusión sobre ese punto para lograr una conclusión completamente equilibrada.
Martin York
1
+1 por explicar por qué, en lugar de decir "No, es una mala práctica".
user253751
42

Entonces, quieres crear un nuevo idioma. Luego hazlo y no paralices C ++.

Hay varias razones para no hacerlo:

  1. Cada estándar de codificación normal sugerirá evitar las macros ( aquí está la razón )
  2. Es más difícil mantener el código con tales macros. Todos los que programan en C ++ saben lo que thises, y al agregar dicha macro, en realidad están agregando una nueva palabra clave. ¿Qué pasa si todos presentan algo que les gusta? ¿Cómo se vería el código?
  3. No debe usarlo (*this).o no usarlo this->, excepto en algunos casos especiales (vea esta respuesta y busque "this->")

Su código no es diferente del #define R returnque vi en el código real. ¿Razón? ¡Menos tipeo!


Yendo un poco fuera del tema, pero aquí voy a ampliar el punto 3 (no usar (*this).o this->en una clase).

En primer lugar, (*this).o this->se utilizan para acceder a las variables miembro o funciones del objeto. Usarlo no tiene sentido y significa escribir más. Además, leer dicho código es más difícil porque hay más texto. Eso significa un mantenimiento más difícil.

Entonces, ¿cuáles son los casos en los que tiene que usar this->?

(a) Selección desafortunada del nombre del argumento.

En este ejemplo, this->es obligatorio, ya que el argumento tiene el mismo nombre que la variable miembro:

struct A {
  int v;
  void foo( int v ) {
    this->v =v;
  }
};

(b) Cuando se trata de plantillas y herencia (ver esto )

Este ejemplo no se compilará, porque el compilador no sabe a qué variable se llama vpara acceder.

template< typename T >
struct A {
  A(const T& vValue):v(vValue){}

  T v;
};

template< typename T >
struct B : A<T>
{
    B(const T& vValue):A<T>(vValue){}

    void foo( const T & newV ) {
      v = newV;
    }
};
BЈовић
fuente
1
"Entonces, quieres crear un nuevo lenguaje. Luego hazlo y no paralices a c ++". - Estoy en desacuerdo. Una fortaleza importante de C y C ++ es su flexibilidad. El OP no está paralizando C ++, solo utiliza su flexibilidad de una manera particular para facilitarle la codificación.
user253751
2
@immibis Derecha. Lo que es más fácil para él, es más difícil para todos los demás. Cuando trabajas en un equipo, poner esas tonterías en el código no te hará muy favorable.
Bћовић
2
Su respuesta no es diferente de "define son malvados".
Sr. Lister el
77
@MrLister Mi respuesta es "estúpido define son malvados". La macro en la pregunta es estúpida de usar, y como mostré, no es necesaria en absoluto. El código es bueno e incluso mejor sin *this.ythis->
BЈовић
1
@Mehrdad ¿La gente todavía agrega prefijos y sufijos a las variables miembro? Pensé que estaba "arreglado" con libros como Clean Code . this->es tan útil como autoen pre-c ++ 11. En otras palabras, solo aumenta el ruido del código.
Bћовић
26

Sugiero no hacer esto. Esto le da a un lector que no está familiarizado con su macro un gran " WTF " cada vez que ve esto. El código no se vuelve más legible al inventar "nuevas convenciones" sobre las generalmente aceptadas sin ninguna necesidad real.

usar esto-> en todas partes es demasiado ruidoso y feo

Eso puede parecerle así, tal vez porque hizo mucha programación en lenguajes usando la palabra clave me(¿Visual Basic, supongo?). Pero, de hecho, es solo una cuestión de acostumbrarse, this->es bastante corto, y creo que la mayoría de los programadores experimentados de C ++ no estarán de acuerdo con su opinión. Y en el caso anterior, ni el uso this->ni el uso de mees apropiado: obtienes la menor cantidad de desorden al dejar esas palabras clave al acceder a los miembros de datos dentro de las funciones de miembro.

Si desea que sus variables de miembros privados se distingan de las locales, agregue algo m_como un prefijo o un guión bajo como sufijo (pero como puede ver aquí , incluso esta convención es "demasiado ruidosa" para muchas personas).

Doc Brown
fuente
12
_debe ser sufijo ; como prefijo está reservado para símbolos internos de bibliotecas estándar y extensiones de proveedores.
Jan Hudec
44
@ JanHudec Solo si comienza con __(dos guiones bajos) o un guión bajo seguido de una letra mayúscula. Un solo guión bajo seguido de una letra minúscula está bien, siempre que no esté en el espacio de nombres global.
Eric Finn
1
@EricFinn: Combiné las dos reglas en una. Dos guiones bajos o guiones bajos seguidos de mayúscula son para símbolos internos y un guión bajo seguido de minúscula es para extensiones específicas del sistema. Las aplicaciones tampoco deberían usarse.
Jan Hudec
@ JanHudec no conocía la regla para extensiones específicas del sistema. Sin embargo, dejaré mi comentario anterior para proporcionar un contexto para su comentario.
Eric Finn
2
@ JanHudec: ¿Minúsculas es para extensiones específicas del sistema? ¿Podría publicar una referencia a la parte del estándar C ++ que indica esto?
Mehrdad
18

Por favor no lo hagas! Estoy tratando de hacer frente a una gran base de código donde las macros están por todas partes para guardar la escritura. Lo malo de redefinir esto para mí es que el preprocesador lo reemplazará en todas partes, incluso cuando esto no esté dentro del alcance / no se aplique, por ejemplo, una función independiente, su colega colega podría tener una variable local llamada en otro lugar ... (s) no será feliz depurando ... Terminas teniendo macros que no puedes usar en todos los ámbitos.

truschival
fuente
6

¡NO!

Solo imagine la confusión que ocurrirá si alguien # incluye ese encabezado, sin conocer su truco, y en otra parte de su archivo tienen una variable o función llamada "yo". Estarían terriblemente confundidos por cualquier mensaje de error inescrutable que se imprima.

Larry Gritz
fuente
En la práctica, es muy probable que pasen el mouse sobre "yo" con su IDE y vean la definición.
user253751
2
@immibis: En la práctica, sin embargo, también es probable que digan algo como "¿quién escribió esta basura?". : P
cHao
@immibis: la mayoría de los codificadores principales con los que trabajo no usan el mouse, es demasiado lento.
JBRWilkinson
De hecho: empujar esto en un encabezado es el problema real. Si lo usa en su archivo cpp, no veo ningún problema en absoluto. Si tuviéramos el pragma push como estándar, estaría aconsejando cómo hacer esto en un encabezado, pero no lo hacemos. Repite después de mi. #defines son globales.
Joshua