Это хорошая идея для указателей typedef?

336
36

Я просмотрел какой-то код и заметил, что соглашение состоит в том, чтобы включить типы указателей, например


SomeStruct* 

в


typedef SomeStruct* pSomeStruct;

Есть ли в этом заслуга?

спросил(а) 2009-04-15T06:14:00+04:00 11 лет, 7 месяцев назад
1
Решение
400

Это может быть уместно, когда сам указатель можно рассматривать как "черный ящик", то есть часть данных, внутреннее представление которых не должно иметь отношения к коду.

По сути, если ваш код никогда не разыменует указатель, и вы просто передаете его функциям API (иногда по ссылке), тогда typedef не только уменьшает количество * в вашем коде, но также предлагает программисту, что указатель не должен на самом деле не вмешиваться.

Это также облегчает изменение API в будущем, если возникнет такая необходимость. Например, если вы переключитесь на использование идентификатора, а не указателя (или наоборот), существующий код не будет поврежден, потому что указатель никогда не должен был разыменовываться с самого начала.

ответил(а) 2009-04-15T06:28:00+04:00 11 лет, 7 месяцев назад
334

Не в моем опыте. Скрытие "*" делает код трудным для чтения.

ответил(а) 2009-04-15T06:17:00+04:00 11 лет, 7 месяцев назад
213

Единственный раз, когда я использую указатель внутри typedef, - это иметь дело с указателями на функции:



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


typedef void (*SigCatcher)(int);

SigCatcher old = signal(SIGINT, SIG_IGN);


В противном случае я считаю их более запутанными, чем полезными.



<Я > Выделенная декларация является правильным типом для указателя на функцию signal(), а не на ловушку сигнала. Его можно было бы уточнить (используя скорректированный тип SigCatcher выше), написав:
 typedef SigCatcher (*SignalFunction)(int, SigCatcher);

Или, чтобы объявить функцию signal():


 extern SigCatcher signal(int, SigCatcher);

То есть a SignalFunction является указателем на функцию, которая принимает два аргумента (a int и a SigCatcher) и возвращает a SigCatcher. А сама signal() - это функция, которая принимает два аргумента (a int и a SigCatcher) и возвращает a SigCatcher.

ответил(а) 2009-04-15T06:34:00+04:00 11 лет, 7 месяцев назад
170

Это поможет избежать некоторых ошибок. Например, в следующем коде:


int* pointer1, pointer2;

pointer2 не является int *, он просто int.
Но с typedefs это не произойдет:


typedef int* pInt;
pInt pointer1, pointer2;

Теперь они int *.

ответил(а) 2009-04-15T06:52:00+04:00 11 лет, 7 месяцев назад
118

Мой ответ - "Нет".

Зачем?

Ну, во-первых, вы просто меняете один символ * на другой символ p. Это нулевое усиление. Одно это должно удерживать вас от этого, так как всегда плохо делать лишние бессмысленные вещи.

Во-вторых, и это важная причина, * несет значение, которое нехорошо скрывать. Если я передам что-то в функцию, как это

void foo(SomeType bar);

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

Я не ожидаю, что значение myBar изменится, передав его в foo(). В конце концов, я myBar по значению, так что foo() только когда-либо видит копию myBar верно? Не тогда, когда SomeType имеет псевдоним, чтобы обозначать какой-то указатель!

Это относится как к указателям на C, так и к интеллектуальным указателям C++: если вы скрываете тот факт, что они являются указателями для ваших пользователей, вы создадите путаницу, которая совершенно не нужна. Поэтому, пожалуйста, не используйте псевдонимы.

(Я считаю, что привычка определять типы указателей - просто ошибочная попытка скрыть, сколько звезд у программиста http://wiki.c2.com/?ThreeStarProgrammer.)

ответил(а) 2017-04-10T00:40:00+03:00 3 года, 7 месяцев назад
102

Он (как и многие ответы) зависит.


В C это очень распространено, поскольку вы пытаетесь замаскировать, что объект является указателем. Вы пытаетесь понять, что это объект, которым управляют все ваши функции (мы знаем, что это указатель внизу, но он представляет объект, который вы манипулируете).


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

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


Под MYDB, вероятно, указатель на некоторый объект.


В С++ это больше не требуется.

Главным образом потому, что мы можем передавать информацию по ссылке и методы включены в объявление класса.


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.

ответил(а) 2009-04-15T07:45:00+04:00 11 лет, 7 месяцев назад
92

Typedef используется, чтобы сделать код более читаемым, но создание указателя в качестве typedef приведет к увеличению путаницы. Лучше избегать указателей typedef.

ответил(а) 2009-04-15T06:55:00+04:00 11 лет, 7 месяцев назад
92

Это вопрос стиля. Этот код очень часто встречается в заголовочных файлах Windows. Хотя они, как правило, предпочитают всю версию верхнего регистра вместо префикса с нижним регистром p.


Лично я избегаю использования typedef. Гораздо понятнее, что пользователь явно говорит, что хочет Foo *, чем PFoo. Typedef лучше всего подходят для чтения STL:)


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

ответил(а) 2009-04-15T06:19:00+04:00 11 лет, 7 месяцев назад
84

Если вы сделаете это, вы не сможете создавать контейнеры STL для const pSomeStruct, поскольку компилятор читает:


list<const pSomeStruct> structs;

а


list<SomeStruct * const> structs;

который не является законным контейнером STL, поскольку элементы не могут быть назначены.


См. этот вопрос .

ответил(а) 2010-01-27T20:24:00+03:00 10 лет, 10 месяцев назад
71

Обсуждение поставлено в предположении, что язык, представляющий интерес, является C. Рамификации для С++ не рассматриваются.


Использование указателя typedef для немаркированной структуры


Вопрос Размер структуры, определяемой как указатель, вызывает интересный боковой свет при использовании указателей typedef для (структуры).


Рассмотрим определение типа безводного бетона (не непрозрачного):


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

Детали участников полностью касаются этого обсуждения; все дело в том, что это не непрозрачный тип типа typedef struct tag *tag; (и вы не можете определить такие непрозрачные типы через typedef без тега).


Возникает вопрос: "Как вы можете найти размер этой структуры"?


Короткий ответ "только через переменную типа". Нет тега для использования с sizeof(struct tag). Например, вы не можете написать sizeof(*Information) , а sizeof(Information *) - размер указателя на тип указателя, а не размер типа структуры.


Фактически, если вы хотите выделить такую ​​структуру, вы не сможете создать ее, кроме как через динамическое распределение (или суррогатные методы, имитирующие динамическое распределение). Невозможно создать локальную переменную типа структуры, указатели которой называются Information, и нет способа создать переменную типа файла (глобальную или static) типа структуры, а также нет способа встроить такую ​​структуру (в отличие от указателя на такую ​​структуру) в другую структуру или тип объединения.


Вы можете - должны написать:


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

Помимо того, что указатель скрыт в typedef, это хорошая практика - если тип info изменится, распределение размеров останется точным. Но в этом случае это также единственный способ получить размер структуры и выделить структуру. И нет другого способа создать экземпляр структуры.


Это вредно?


Это зависит от ваших целей.


Это не непрозрачный тип - детали структуры должны быть определены, когда тип указателя typedef 'd.


Это тип, который может использоваться только с распределением динамической памяти.


Это тип, который является безымянным. Указатель на тип структуры имеет имя, но сам тип структуры не работает.


Если вы хотите обеспечить динамическое распределение, это, по-видимому, способ сделать это.


В целом, тем не менее, это скорее вызовет путаницу и тоску, чем просветление.


Резюме


В общем, плохая идея использовать typedef для определения указателя на тип тегов без тегов.

ответил(а) 2017-04-09T22:52:00+03:00 3 года, 7 месяцев назад
73

Win32 API делает это примерно с каждой структурой (если не все)


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

Неплохо, как это согласовано, но, на мой взгляд, оно не добавляет никакой элегантности.

ответил(а) 2009-04-15T06:42:00+04:00 11 лет, 7 месяцев назад
59

Некоторое время назад я ответил бы "нет" на этот вопрос. Теперь, с появлением умных указателей, указатели не всегда определяются звездочкой '*'. Таким образом, нет ничего очевидного в том, что тип является указателем или нет.


Итак, теперь я бы сказал: это хорошо для указателей typedef, если будет ясно, что это "тип указателя". Это означает, что вам нужно использовать префикс/суффикс специально для него. Нет, например, "p" не является достаточным префиксом. Я бы, наверное, пошел с "ptr".

ответил(а) 2009-04-15T08:55:00+04:00 11 лет, 7 месяцев назад
42

Нет.

Это сделает вашу жизнь несчастной момент, когда вы смешать его с const

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

Являются ли bar1 и bar2 одним и тем же типом?

ответил(а) 2019-01-16T11:57:00+03:00 1 год, 10 месяцев назад
42

Цель с typedef заключается в том, чтобы скрыть детали реализации, но типизация свойства указателя слишком много скрывает и делает код более трудным для чтения/понимания.
Поэтому, пожалуйста, не делайте этого.


Если вы хотите скрыть детали реализации (что часто бывает полезно), не скрывайте часть указателя. Возьмем, к примеру, прототип стандартного интерфейса FILE:


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

здесь fopen возвращает указатель на некоторую структуру FILE (о которой вы не знаете детали реализации). Возможно, FILE не такой хороший пример, потому что в этом случае он мог бы работать с некоторым типом pFILE, который скрывал тот факт, что это указатель.


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

Однако это будет работать только потому, что вы никогда не обходитесь с контентом, на который указывают напрямую. В тот момент, когда вы напечатали какой-то указатель на то, что некоторые места меняют код, очень трудно прочитать в моем опыте.

ответил(а) 2009-04-15T14:56:00+04:00 11 лет, 7 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема