É uma boa idéia "#define me (* this)"?

19

Essa macro pode ser definida em algum cabeçalho global, ou melhor, como um parâmetro da linha de comando do compilador:

#define me (*this)

E algum exemplo 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;  
};

Portanto, em um método de classe, quando acesso um membro da classe, estou sempre usando mee, ao acessar um identificador global, sempre uso ::. Isso fornece ao leitor que não está familiarizado com o código (provavelmente eu mesmo depois de alguns meses) informações localizadas sobre o que é acessado sem a necessidade de procurar em outro lugar. Eu quero definir meporque acho que o uso em this->todos os lugares é muito barulhento e feio. Mas pode #define me (*this)ser considerada uma boa prática de C ++? Existem alguns pontos problemáticos práticos com a memacro? E se você, como programador de C ++, será o leitor de algum código usando a memacro, gostaria ou não?

Edit: Porque muitas pessoas argumentam não especificamente contra o uso me, mas geralmente contra isso explícito. Eu acho que pode não estar claro quais são os benefícios de "isso explícito em todos os lugares".

Quais são os benefícios de "explícito isso em todos os lugares"?

  • Como leitor do código, você tem certeza do que é acessado e pode se concentrar em coisas diferentes do que verificar - em algum código distante - que realmente é acessado o que você acha que é acessado.
  • Você pode usar a função de pesquisa mais especificamente. A pesquisa " this->x" pode fornecer mais resultados desejados do que apenas a pesquisa " x"
  • Quando você está excluindo ou renomeando algum membro, o compilador o notifica de maneira confiável nos locais onde esse membro é usado. (Algumas funções globais podem ter o mesmo nome e existir a chance de introduzir erros se você não estiver usando isso explicitamente).
  • Quando você está refatorando o código e tornando a função não membro do membro (para tornar o encapsulamento melhor) explícito, isso mostra o local que você deve editar e pode facilmente substituí-lo pelo ponteiro para a instância da classe fornecida como parâmetro da função não membro
  • Geralmente, quando você está alterando o código, há mais possibilidades de erros quando você não está usando isso explícito do que quando você está usando isso explícito em qualquer lugar.
  • Explícito, isso é menos barulhento que o explícito "m_" quando você acessa um membro de fora ( object.membervs object.m_member) (graças a @Kaz para identificar este ponto)
  • Explícito, isso resolve o problema universalmente para todos os membros - atributos e métodos, enquanto „m_“ ou outro prefixo é praticamente utilizável apenas para atributos.

Gostaria de polir e estender esta lista, me diga se você conhece outras vantagens e casos de uso para explicitar isso em todos os lugares .

user3123061
fonte
3
Você deve evitar argumentos de função e membros com o mesmo nome, além de evitar "isto" explícito.
Pjc50
4
Lembra-me do código VB do meu chefe. Me Me Me em todo lugar. Parece egoísta. : p De qualquer forma, as respostas até agora dizem tudo.
MetalMikester 14/07
19
É uma ideia maravilhosa! E para aqueles que têm experiência em Python, por que não #define self (*this)? Você pode até misturar as duas macros e ter alguns arquivos que imitam o VB e outros Python. :)
logc 14/07
11
Porque não basta ir tudo para fora, e fazer: #include "vb.h", #Include pascal.h, ou #include FOTRAN.he ter a próxima pessoa a tocar o seu código de submetê-lo a TDWTF .
Dan Neely
4
Oh, por favor, apenas não. Você pode evitar alguns problemas apenas declarando atributos como me_x.
Gort the Robot

Respostas:

90

Não não é.

Lembre-se do programador que manterá seu código daqui a alguns anos, muito tempo depois de partir para pastos mais ecológicos e seguir as convenções comuns do idioma que você usa. No C ++, você quase nunca precisa escrever this, porque a classe está incluída na ordem de resolução de símbolos e, quando um símbolo é encontrado no escopo da classe, this->está implícito. Portanto, não escreva como todo mundo faz.

Se você costuma ficar confuso sobre quais símbolos vêm do escopo da classe, a abordagem usual é usar o padrão de nomenclatura comum para membros (campos e, às vezes, métodos privados; eu não o vi usado para métodos públicos). Os mais comuns incluem sufixo _ou prefixo com m_ou m.

Jan Hudec
fonte
12
"Em C ++, você quase nunca precisa escrever isso", que é uma convenção totalmente não relacionada à questão. Algumas pessoas (como eu) preferem escrever thispara deixar explicitamente claro que a variável não é local para o método. A questão aqui é sobre se a macro medeve existir, não se thisé algo que deve ser usado.
Mehrdad 14/07
8
@ Mehrdad: Porque o OP diz explicitamente que ele está usando em me.vez de this->. Como não há necessidade, this->não há necessidade me.e, portanto, não há necessidade para a macro.
Martin York
11
@LokiAstari: Nada na pergunta nem remotamente sugere o OP se perguntando se this->"é necessário". De fato, o OP diz que está usando this->, apesar de não ser necessário. A questão é se me.deve ser usado em vez de this-> , o que esta resposta não responde de fato.
Mehrdad
4
@ Mehrdad: Mas apenas colocar sim ou não é uma resposta muito chata. Assim, as explicações são geralmente bastante úteis para explicar como a resposta é alcançada (é incentivada por Como responder ). A conclusão não deve ser usada porque o OP tem a atitude errada para começar sobre o uso thise, portanto, é necessária uma discussão sobre esse ponto para obter uma conclusão totalmente equilibrada.
Martin York
1
+1 por explicar o motivo, em vez de apenas dizer "Não, é uma prática ruim".
user253751
42

Então, você deseja criar um novo idioma. Em seguida, faça isso e não aleije o C ++.

Existem várias razões para não fazer isso:

  1. Todo padrão de codificação normal sugere evitar macros ( eis o porquê )
  2. É mais difícil manter o código com essas macros. Todo mundo que programa em C ++ sabe o que thisé e, ao adicionar essa macro, você está realmente adicionando uma nova palavra-chave. E se todos apresentarem algo de que gostem? Como seria o código?
  3. Você não deve usar (*this).ou this->em tudo, exceto em alguns casos especiais (ver esta resposta e procure por "this->")

Seu código não é diferente do #define R returnque eu vi no código real. Razão? Menos digitação!


Indo um pouco fora do assunto, mas aqui vou expandir o ponto 3 (não use (*this).ou this->em uma classe).

Primeiro de tudo, (*this).ou this->são usados ​​para acessar variáveis-membro ou funções do objeto. Usá-lo não tem sentido e significa mais digitação. Além disso, a leitura desse código é mais difícil, porque há mais texto. Isso significa manutenção mais difícil.

Então, quais são os casos em que você precisa usar this->?

(a) Escolha infeliz do nome do argumento.

Neste exemplo, this->é necessário, pois o argumento tem o mesmo nome que a variável de membro:

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

(b) Ao lidar com modelos e herança (veja isso )

Este exemplo falhará na compilação, porque o compilador não sabe qual variável chamada vpara acessar.

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Јовић
fonte
1
"Então, você deseja criar um novo idioma. Em seguida, faça-o e não prejudique o c ++." - Discordo. Um dos principais pontos fortes de C e C ++ é a flexibilidade. O OP não está paralisando o C ++, apenas utilizando sua flexibilidade de uma maneira específica para facilitar a codificação.
user253751
2
@immibis Certo. O que é mais fácil para ele, é mais difícil para todo mundo. Quando você trabalha em equipe, colocar essas bobagens no código não o tornará muito favorável.
21414
2
Sua resposta não é diferente de "define são maus".
Sr. Lister
7
@ MrLister Minha resposta é "define estúpido é mau". A macro da pergunta é estúpida de usar e, como mostrei, não é necessária. O código é bom e ainda melhor sem *this.e #this->
01/07
1
@Mehrdad As pessoas ainda estão adicionando prefixos e sufixos às variáveis ​​de membro? Eu pensei que isso era "consertado" com livros como o Clean Code . this->é tão útil quanto autono pré-c ++ 11. Em outras palavras, apenas aumenta o ruído do código.
BЈовић
26

Eu sugiro não fazer isso. Isso dá a um leitor que não está familiarizado com sua macro um grande " WTF " sempre que ele vê isso. O código não fica mais legível ao inventar "novas convenções" em detrimento das geralmente aceitas, sem nenhuma necessidade real.

usar isso-> em todo lugar é muito barulhento e feio

Pode parecer isso para você, talvez porque você tenha feito muita programação em linguagens usando a palavra-chave me(Visual Basic, eu acho?). Mas, na verdade, é apenas uma questão de se acostumar com isso - this->é bem curto, e acho que a maioria dos programadores experientes em C ++ discordará da sua opinião. E no caso acima, nem o uso this->nem o uso de mesão apropriados - você obtém a menor quantidade de confusão, deixando essas palavras-chave de fora ao acessar membros de dados dentro das funções de membro.

Se você deseja que suas variáveis ​​de membro privadas sejam distinguidas das variáveis ​​locais, adicione algo m_como prefixo ou um sublinhado como sufixo (mas como você pode ver aqui , mesmo essa convenção é "muito barulhenta" para muitas pessoas).

Doc Brown
fonte
12
_deve ser um sufixo ; como prefixo, é reservado para símbolos internos de bibliotecas padrão e extensões de fornecedores.
Jan Hudec
4
@JanHudec Somente se começar com __(dois sublinhados) ou um sublinhado seguido de uma letra maiúscula. Um único sublinhado seguido por uma letra minúscula é bom, desde que não esteja no espaço de nomes global.
11118 Eric Finn
1
@ EricFinn: eu combinei as duas regras para uma. Dois sublinhados ou sublinhados seguidos por letras maiúsculas são para símbolos internos e um sublinhado único seguido por letras minúsculas é para extensões específicas do sistema. Os aplicativos também não devem ser usados.
Jan Hudec
@JanHudec Não conhecia a regra para extensões específicas do sistema. Deixarei meu comentário anterior para fornecer algum contexto para seu comentário.
11134 Eric Finn
2
@JanHudec: minúsculas são para extensões específicas do sistema? Você poderia postar uma referência à parte do padrão C ++ que indica isso?
21714 Mehrdad
18

Por favor, não faça isso! Estou tentando lidar com uma grande base de código em que as macros estão por todo o lado para economizar digitação. O lado ruim de redefinir isso para mim é que o pré-processador irá substituí-lo em qualquer lugar, mesmo que isso não esteja no escopo / não se aplique, por exemplo, uma função autônoma, seu colega poderá ter uma variável local chamada me em outro lugar .. Você não terá prazer em depurar ... Você acaba tendo macros que não podem ser usadas em todos os escopos.

truschival
fonte
6

NÃO!

Imagine a confusão que ocorrerá se alguém # incluir esse cabeçalho, sem saber o seu truque, e em outro lugar do arquivo eles tiverem uma variável ou função chamada "eu". Eles ficariam terrivelmente confusos com qualquer mensagem de erro inescrutável que seria impressa.

Larry Gritz
fonte
Na prática, é bem provável que passe o mouse sobre "eu" com o IDE e veja a definição.
user253751
2
@immibis: Na prática, é provável que eles digam algo como "quem escreveu essa porcaria?". : P
cHao
@immibis: a maioria dos codificadores principais com os quais trabalho não usa o mouse - é muito lento.
JBRWilkinson
De fato: empurrar isso em um cabeçalho é o problema real. Se você usá-lo no seu arquivo cpp, não vejo problema algum. Se tivéssemos o pragma push como padrão, eu recomendaria como fazer isso em um cabeçalho, mas não o fazemos. Repita depois de mim. #defines são globais.
31717 Joshua