È una buona idea "#define me (* this)"?


19

Questa macro può essere definita in alcune intestazioni globali, o meglio, come parametro della riga di comando del compilatore:

#define me (*this)

E qualche esempio di utilizzo:

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;  
};

Quindi, in un metodo di classe quando accedo a un membro della classe, lo uso sempre mee quando accedo a un identificatore globale lo uso sempre ::. Ciò fornisce al lettore che non ha familiarità con il codice (probabilmente io stesso dopo alcuni mesi) informazioni localizzate di ciò a cui si accede senza la necessità di cercare altrove. Voglio definirlo meperché trovo che usare this->ovunque sia troppo rumoroso e brutto. Ma può #define me (*this)essere considerata una buona pratica C ++? Ci sono alcuni punti pratici problematici con la memacro? E se tu come programmatore C ++ sarai il lettore di un codice usando la memacro, ti piacerebbe o no?

Modifica: Perché molte persone non sostengono specificatamente il contrario me, ma generalmente lo spiegano. Penso che potrebbe non essere chiaro quali siano i vantaggi di "esplicito questo ovunque".

Quali sono i vantaggi di "esplicito questo ovunque"?

  • Come lettore del codice hai la certezza di ciò a cui accedi e puoi concentrarti su cose diverse rispetto a verificare - in un codice distante - a cui si accede realmente a ciò che pensi sia accessibile.
  • È possibile utilizzare la funzione di ricerca in modo più specifico. La ricerca " this->x" può darti più risultati desiderati della sola ricerca " x"
  • Quando si elimina o rinomina un membro, il compilatore ti avvisa in modo affidabile nei luoghi in cui viene utilizzato questo membro. (Alcune funzioni globali possono avere lo stesso nome ed esiste la possibilità che tu possa introdurre un errore se non lo usi esplicitamente).
  • Quando si esegue il refactoring del codice e si rende esplicita la funzione non membro dal membro (per rendere migliore l'incapsulamento), questo mostra il posto che è necessario modificare e si può facilmente sostituirlo con il puntatore all'istanza della classe fornita come parametro della funzione non membro
  • Generalmente quando si modifica il codice, ci sono più possibilità di errori quando non si utilizza esplicitamente questo rispetto a quando si utilizza esplicitamente questo ovunque.
  • Esplicito, questo è meno rumoroso di esplicito "m_" quando si accede a un membro esterno ( object.membervs object.m_member) (grazie a @Kaz per individuare questo punto)
  • Esplicito questo risolve il problema dell'universalità per tutti i membri - attributi e metodi, mentre "m_" o altri prefissi sono praticamente utilizzabili solo per gli attributi.

Vorrei lucidare ed estendere questo elenco, dimmi se sei a conoscenza di altri vantaggi e utilizzare casi per esplicitare questo ovunque .


3
Si dovrebbe evitare di avere argomenti di funzione e membri con lo stesso nome, nonché di evitare "questo" esplicito.
pjc50,

4
Mi ricorda il codice VB del mio capo. Me Me Me ovunque. Sembra egoista. : p Comunque, le risposte finora dicono tutto.
MetalMikester,

19
È un'idea meravigliosa! E per coloro che provengono da uno sfondo Python, perché no #define self (*this)? Puoi anche mescolare entrambe le macro e avere alcuni file che imitano VB e altri Python. :)
logc

11
Perché non andare tutti fuori, e fare: #include "vb.h", #Include pascal.h, o #include FOTRAN.he hanno la persona accanto a toccare il codice sottopone al TDWTF .
Dan Neely,

4
Oh per favore, proprio no. Potresti risparmiare qualche problema dichiarando semplicemente gli attributi come me_x.
Gort the Robot,

Risposte:


90

No non lo è.

Pensa al programmatore che manterrà il tuo codice tra qualche anno molto tempo dopo che sei partito per pascoli più verdi e segui le convenzioni comuni della lingua che usi. In C ++, non devi quasi mai scrivere this, perché la classe è inclusa nell'ordine di risoluzione dei simboli e quando un simbolo viene trovato nell'ambito della classe, this->è implicito. Quindi non scriverlo come fanno tutti.

Se vieni spesso confuso su quali simboli provengono dall'ambito della classe, l'approccio abituale è quello di utilizzare un modello di denominazione comune per i membri (campi e talvolta metodi privati; non l'ho visto usato per metodi pubblici). Quelli comuni includono il suffisso _o il prefisso con m_o m.


12
"In C ++, non devi quasi mai scrivere questo" che è una convenzione totalmente indipendente dalla domanda. Alcune persone (come me) preferiscono scrivere thisper chiarire esplicitamente che la variabile non è locale al metodo. La domanda qui è se la macro medovrebbe esistere, non se thisè qualcosa che dovrebbe essere usato.
Mehrdad,

8
@Mehrdad: Perché l'OP dice esplicitamente che sta usando me.invece di this->. Poiché non è necessario, this->non è necessario me.e quindi non è necessario per la macro.
Martin York,

11
@LokiAstari: Nulla nella domanda suggerisce nemmeno in remoto il PO chiedendosi se this->"è necessario". In effetti, l'OP afferma che lo sta usando this->nonostante non sia necessario. La domanda è se me.debba essere usato al posto di this-> , a cui questa risposta non risponde realmente.
Mehrdad,

4
@Mehrdad: Ma solo mettere sì o no rende una risposta molto noiosa. Quindi le spiegazioni sono di solito abbastanza utili per spiegare come viene raggiunta la risposta (è incoraggiata da Come rispondere ). La conclusione non è da usare perché l'OP ha l'atteggiamento sbagliato di iniziare sull'uso thise quindi è necessaria una discussione su questo punto per ottenere una conclusione pienamente equilibrata.
Martin York,

1
+1 per spiegare perché, invece di dire semplicemente "No, è una cattiva pratica".
user253751

42

Quindi, vuoi creare una nuova lingua. Quindi fallo e non paralizzare C ++.

Esistono diversi motivi per non farlo:

  1. Ogni normale standard di codifica suggerirà di evitare le macro ( ecco perché )
  2. È più difficile mantenere il codice con tali macro. Tutti coloro che programmano in C ++ sanno cos'è this, e aggiungendo tale macro, in realtà stai aggiungendo una nuova parola chiave. E se tutti introducessero qualcosa che gli piace? Come sarebbe il codice?
  3. Non dovresti usare (*this).o this->affatto, tranne in alcuni casi speciali (vedi questa risposta e cerca "this->")

Il tuo codice non è diverso da quello #define R returnche ho visto nel codice attuale. Motivo? Meno battitura!


Andando leggermente fuori tema, ma qui ho intenzione di espandere il punto 3 (non usare (*this).o this->in una classe).

Prima di tutto, (*this).o this->vengono utilizzati per accedere alle variabili membro o alle funzioni dell'oggetto. Usarlo non ha senso e significa scrivere di più. Inoltre, leggere questo codice è più difficile, perché c'è più testo. Ciò significa una manutenzione più difficile.

Quindi, quali sono i casi in cui devi usare this->?

(a) Sfortunata scelta del nome dell'argomento.

In questo esempio, this->è richiesto, poiché l'argomento ha lo stesso nome della variabile membro:

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

(b) Quando si tratta di modelli ed ereditarietà (vedere questo )

Questo esempio non verrà compilato, poiché il compilatore non sa a quale variabile denominata vaccedere.

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;
    }
};

1
"Quindi, vuoi creare un nuovo linguaggio. Quindi fallo e non paralizzare c ++." - Non sono d'accordo. Un punto di forza di C e C ++ è la loro flessibilità. L'OP non sta paralizzando C ++, ma solo sfruttando la sua flessibilità in un modo particolare per renderlo più facile da codificare.
user253751

2
@immibis Right. Ciò che è più facile per lui, è più difficile per tutti gli altri. Quando lavori in gruppo, inserire queste assurdità nel codice non ti renderà molto favorevole.
BЈовић,

2
La tua risposta non è diversa da "definisce il male".
Mr Lister,

7
@MrLister La mia risposta è "stupido definisce il male". La macro nella domanda è stupida da usare e, come ho dimostrato, non è affatto necessaria. Il codice è buono e ancora meglio senza *this.ethis->
BЈовић

1
@Mehrdad Le persone continuano ad aggiungere prefissi e suffissi alle variabili membro? Ho pensato che fosse "riparato" con libri come Clean Code . this->è utile come autoin pre-c ++ 11. In altre parole, aumenta solo il rumore del codice.
BЈовић,

26

Suggerisco di non farlo. Questo dà a un lettore che non ha familiarità con la tua macro un grande " WTF " ogni volta che lo vede. Il codice non diventa più leggibile quando si inventano "nuove convenzioni" rispetto a quelle generalmente accettate senza alcuna reale necessità.

usare questo-> ovunque è troppo rumoroso e brutto

Potrebbe sembrarti così, forse perché hai programmato molto nei linguaggi usando la parola chiave me(Visual Basic, immagino?). Ma in realtà è solo una questione di abituarsi ad esso - this->è piuttosto breve, e penso che la maggior parte dei programmatori C ++ esperti non saranno d'accordo con la tua opinione. E nel caso sopra, né l'uso this->né l'uso di mesono appropriati - ottieni la minima quantità di disordine lasciando quelle parole chiave fuori quando accedi ai membri dei dati all'interno delle funzioni dei membri.

Se vuoi che le variabili dei tuoi membri privati ​​siano distinte da quelle locali, aggiungi qualcosa m_come link a un prefisso o un trattino basso come suffisso (ma come puoi vedere qui , anche questa convenzione è "troppo rumorosa" per molte persone).


12
_dovrebbe essere suffisso ; come prefisso è riservato ai simboli interni delle librerie standard e delle estensioni del fornitore.
Jan Hudec,

4
@JanHudec Solo se inizia con __(due trattini bassi ) o un trattino basso seguito da una lettera maiuscola. Un singolo trattino basso seguito da una lettera minuscola va bene, purché non sia nello spazio dei nomi globale.
Eric Finn,

1
@EricFinn: ho combinato le due regole in una. Due caratteri di sottolineatura o di sottolineatura seguiti da lettere maiuscole sono per i simboli interni e un carattere di sottolineatura singolo seguito da lettere minuscole è per le estensioni specifiche del sistema. Le applicazioni non dovrebbero usare neanche.
Jan Hudec,

@JanHudec Non era a conoscenza della regola per le estensioni specifiche del sistema. Lascio il mio commento precedente per fornire un contesto per il tuo commento, però.
Eric Finn,

2
@JanHudec: le minuscole sono per estensioni specifiche del sistema? Potresti pubblicare un riferimento alla parte dello standard C ++ che indica questo?
Mehrdad,

18

Per favore, non farlo! Sto cercando di far fronte a una grande base di codice in cui le macro sono ovunque per salvare la digitazione. La cosa brutta della ridefinizione di questo per me è che il preprocessore lo sostituirà ovunque anche dove questo non è nell'ambito / non si applica, ad esempio una funzione autonoma, il tuo collega collega potrebbe avere una variabile locale chiamata me da qualche altra parte .. (s) non sarà felice il debug ... Alla fine avrai macro che non puoi usare in tutti gli ambiti.


6

NO!

Immagina solo la confusione che si verificherà se qualcuno # include quell'intestazione, non conoscendo il tuo trucco, e altrove nel loro file hanno una variabile o una funzione chiamata "me". Sarebbero orribilmente confusi da qualunque messaggio di errore imperscrutabile sarebbe stampato.


In pratica, è molto probabile che tocchino "me" con il loro IDE e vedano la definizione.
user253751

2
@immibis: In pratica, però, è probabile che dicano anche qualcosa del tipo "chi ha scritto questa merda?". : P
cHao,

@immibis: la maggior parte dei programmatori migliori con cui lavoro non usa il mouse - è troppo lento.
JBR Wilkinson,

In effetti: spingere questo in un'intestazione è il vero problema. Se lo usi nel tuo file cpp non vedo alcun problema. Se avessimo pragma push di serie, consiglierei come farlo in un colpo di testa, ma non lo facciamo. Ripeti dopo di me. #define sono globali.
Giosuè il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.