Вопрос

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

SomeStruct* 

в

typedef SomeStruct* pSomeStruct;

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

Это было полезно?

Решение

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

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

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

Другие советы

По моему опыту, нет.Скрытие '*' делает код трудным для чтения.

Единственный раз, когда я использую указатель внутри 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);

Это SignalFunction это указатель на функцию, которая принимает два аргумента ( int и SigCatcher) и возвращает SigCatchersignal() сама по себе является функцией, которая принимает два аргумента ( int и SigCatcher) и возвращает SigCatcher.

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

int* pointer1, pointer2;

указатель2 не является интервал *, это просто интервал.Но с typedefs этого не произойдет:

typedef int* pInt;
pInt pointer1, pointer2;

Они оба интервал * сейчас.

Мой ответ – однозначное «Нет».

Почему?

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

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

void foo(SomeType bar);

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

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

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

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

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

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

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

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

В 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, вероятно, находится указатель на какой-то объект.

В C++ это больше не требуется.
Главным образом потому, что мы можем передавать данные по ссылке, а методы включены в объявление класса.

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 используется для того, чтобы сделать код более читабельным, но использование указателя в виде typedef увеличит путаницу.Лучше избегать указателей typedef.

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

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

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

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

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

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

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

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

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

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

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

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

Вредно ли это?

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

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

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

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

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

Однако в целом это скорее вызовет замешательство и тревогу, чем просветление.

Краткие сведения

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

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

list<const pSomeStruct> structs;

как

list<SomeStruct * const> structs;

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

Видеть это вопрос .

Нет.

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

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

Являются bar1 и bar2 того же типа?

И да, я просто цитирую «Гуру» Херба Саттера.Много правды она сказала.;)

-- Редактировать --

Добавление ссылки на цитируемую статью.

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

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

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

Приятно, что это логично, но, на мой взгляд, это не добавляет элегантности.

Цель 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);

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top