Pergunta

Eu olhei através de algum código e notei que a convenção era transformar tipos de ponteiro como

SomeStruct* 

para

typedef SomeStruct* pSomeStruct;

Existe algum mérito para isso?

Foi útil?

Solução

Isto pode ser apropriado quando o ponteiro em si pode ser considerada como uma "caixa preta", ou seja, um pedaço de dados cuja representação interna deve ser irrelevante para o código.

Essencialmente, se o seu código irá não excluir a referência o ponteiro, e você apenas passá-lo em torno de funções da API (por vezes por referência), então não só o typedef reduzir o número de *s no seu código, mas também sugere ao programador que o ponteiro não deve realmente ser rixas.

Isso também torna mais fácil mudar o API no futuro, se surgir a necessidade. Por exemplo, se você mudar para usando um ID em vez de um ponteiro (ou vice-versa) código existente não vai quebrar porque o ponteiro não deveria ser dereferenced em primeiro lugar.

Outras dicas

Não na minha experiência. Escondendo o '*' torna o código difícil de ler.

A única vez que eu usar um ponteiro dentro do typedef é quando se lida com ponteiros para funções:

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

typedef void (*SigCatcher)(int);

SigCatcher old = signal(SIGINT, SIG_IGN);

Caso contrário, eu encontrá-los mais confuso do que útil.


A declaração atingiu-out é do tipo correcto para um apontador para a função signal(), não do apanhador de sinal. Pode ser mais claro (usando o tipo corrigido SigCatcher acima) escrevendo:

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

Ou, para declarar a função signal():

 extern SigCatcher signal(int, SigCatcher);

Ou seja, um SignalFunction é um ponteiro para uma função que leva dois argumentos (um int e uma SigCatcher) e retorna um SigCatcher. E a própria signal() é uma função que recebe dois argumentos (um int e uma SigCatcher) e retorna um SigCatcher.

Isto pode ajudar a evitar alguns erros. Por exemplo, no código a seguir:

int* pointer1, pointer2;

pointer2 não é um int * , é simples int . Mas com typedefs isso não vai acontecer:

typedef int* pInt;
pInt pointer1, pointer2;

Ambos são int * agora.

A minha resposta é um claro "Não".

Por quê?

Bem, primeiro de tudo, você simplesmente trocar um único * caracteres para outro p caráter único. Isso é de zero ganho. Isso por si só deve mantê-lo de fazer isso, pois é sempre ruim para fazer coisas extra que é inútil.

Em segundo lugar, e essa é a razão importante, o * carrega o que significa que não é bom para esconder . Se eu passar algo para uma função como esta

void foo(SomeType bar);

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

Eu não espero que o significado de myBar de ser alterado, passando-a para foo(). Afinal, eu estou passando por valor, de modo foo() só nunca vê uma cópia do myBar certo? Não quando SomeType é alias para significar algum tipo de ponteiro!

Isto aplica-se tanto aos ponteiros C e ponteiros inteligentes C ++: Se você ocultar o fato de que eles são ponteiros para os usuários, você irá criar confusão que é totalmente desnecessário. Então, por favor, não faça apelido seus ponteiros.

(Eu acredito que o hábito de typedefing tipos de ponteiro é apenas uma tentativa equivocada de esconder quantas estrelas tem como programador http://wiki.c2.com/?ThreeStarProgrammer .)

Esta é uma questão de estilo. Você vê este tipo de código muito freqüentemente nos arquivos de cabeçalho do Windows. Embora eles tendem a preferir a versão caso, todos superior, em vez de prefixo com um minúsculas p.

Pessoalmente I evitar este uso de typedef. É muito mais clara para que o usuário explicitamente dizem que querem um Foo * que PFoo. Typedef de são mais adequados nos dias de hoje para fazer STL legível:)

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

It (como tantas respostas) depende.

Em C este é muito comum, como você está tentando disfarçar que um objeto é um ponteiro. Você está tentando dar a entender que este é o objeto que todas as suas funções de manipular (sabemos que é um baixo ponteiro mas representa o objeto que você 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);

Debaixo MYDB é provavelmente um ponteiro em algum objeto.

Em C ++ isso não é mais necessário.
Principalmente porque nós podemos passar as coisas por referência e os métodos são incorporados na declaração da classe.

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.

Typedef é usado para código make mais legível, mas fazendo ponteiro como typedef irá aumentar a confusão. Melhor evitar typedef ponteiros.

Discussão armou assumindo a linguagem de interesse é C. ramificações para C ++ não foram considerados.

Usando um typedef um ponteiro para uma estrutura não marcado

A questão tamanho de uma struct que é definido como um ponteiro levanta uma side-luz interessante sobre o uso typedef para (estrutura ) ponteiros.

Considere o concreto tagless (não opaco) definição do tipo de estrutura:

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

Os detalhes dos membros são completamente tangencial para esta discussão; Tudo o que importa é que este não é um tipo opaco como typedef struct tag *tag; (e você não pode definir esses tipos opacos através de um typedef sem tag).

A questão levantada é 'como você pode encontrar o tamanho dessa estrutura'?

A resposta curta é 'apenas através de uma variável do tipo'. Não há tag para usar com sizeof(struct tag). Você não pode utilmente escrever sizeof(*Information) , por exemplo, e sizeof(Information *) é do tamanho de um ponteiro para o tipo de ponteiro, e não o tamanho do tipo de estrutura.

Na verdade, se você deseja alocar essa estrutura, você não pode criar uma exceção via alocação dinâmica (ou técnicas substitutos que a alocação dinâmica do mímico). Não há maneira de criar uma variável local do tipo de estrutura cujos ponteiros são chamados Information, nem há uma maneira de criar um escopo de arquivo variável do tipo de estrutura (global ou static), nem existe uma maneira de incorporar tais uma estrutura (em oposição a um ponteiro para uma tal estrutura) para uma outra estrutura ou tipo de união.

Você pode - deve - escreve:

Information info = malloc(sizeof(*info));

Além do fato de que o ponteiro está escondido no typedef, esta é uma boa prática - se o tipo de mudanças info, a alocação tamanho vai ficar correcta. Mas, neste caso, é também a única maneira de obter o tamanho da estrutura e alocar a estrutura. E não há outra maneira de criar uma instância da estrutura.

é este prejudicial?

Depende de seus objetivos.

Este não é um tipo opaca -. Os detalhes da estrutura devem ser definidos quando o tipo de ponteiro é typedef'd

É um tipo que só pode ser usado com alocação dinâmica de memória.

É um tipo que é sem nome. O ponteiro para o tipo de estrutura tem um nome, mas o próprio tipo de estrutura não.

Se você deseja impor a alocação dinâmica, esta parece ser uma maneira de fazê-lo.

Em geral, porém, é mais susceptível de causar confusão e angústia de iluminação.

Resumo

É, em geral, uma má idéia para uso typedef para definir um ponteiro para um tipo tagless stucture.

Se você fizer isso, você não será capaz de criar contêineres STL de pSomeStruct const desde o compilador lê:

list<const pSomeStruct> structs;

como

list<SomeStruct * const> structs;

que não é um recipiente STL legal já que os elementos não são transmissíveis.

Veja este questão .

Não.

Ele vai fazer sua vida miserável do momento que você misturá-lo com const

typedef foo *fooptr;
const fooptr bar1;
const foo *bar2

Tem bar1 e bar2 o mesmo tipo?

E sim, estou apenas citando Guru de Herb Sutter. Muita verdade ela falou. ;)

- Edit -

Adicionando link para o artigo citado.

http://www.drdobbs.com/conversationsa-midsummer-nights -madness / 184403835

Win32 API faz isso com apenas sobre cada estrutura (se não todos)

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

É bom como ele é consistente, mas na minha opinião ele não adiciona qualquer elegância.

O objetivo com typedef é para esconder os detalhes de implementação, mas typedef-ing as peles de propriedade ponteiro demais e torna o código mais difícil de ler / entender. Então, por favor, não faça isso.


Se você quiser detalhes esconder de implementação (que muitas vezes é uma boa coisa a fazer), não esconde a parte ponteiro. Tomemos, por exemplo, no protótipo para a interface FILE padrão:

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

Retorna aqui FOPEN um ponteiro para alguns FILE estrutura (que você não sabe os detalhes de implementação para). Talvez FILE não é como um bom exemplo, porque, neste caso, poderia ter trabalhado com algum tipo pfile que escondeu o fato de que é um ponteiro.

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

No entanto, isso só seria trabalho porque você nunca mexer com o conteúdo que é apontado diretamente. No momento em que typedef alguns ponteiro que alguns lugares modificar o código se torna muito difícil de ler na minha experiência.

Algum tempo atrás, eu teria respondido "não" a esta pergunta. Agora, com o surgimento de ponteiros inteligentes, ponteiros nem sempre são definidos com uma estrela '*' anymore. Portanto, não há nada de óbvio sobre um tipo de ser um ponteiro ou não.

Então, agora eu diria: é bom para typedef ponteiros, contanto que ele é muito claro que ele é um "tipo de ponteiro". Isso significa que você tem que usar um prefixo / sufixo especificamente para ele. Não, "p" não é um prefixo suficiente, por exemplo. Eu provavelmente iria com "ptr".

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top