Есть ли практическая разница между использованием непрозрачного указателя и указателя на void?

Подскажите, пожалуйста, если рассматривать реализацию API библиотеки (в C стиле), то есть ли какая-нибудь разница (в практическом смысле) между непрозрачным указателем и указателем на void?


Ответы (1 шт):

Автор решения: Chorkov

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

Сравните:

  typedef void* HTexture;
  typedef void* HTransformation;
  void transformTexture( HTexture texture, HTransformation transformation);


  struct Texture; 
  typedef Texture* HTexture;
  struct Transformation;
  typedef Transformation* HTransformation;
  void transformTexture( HTexture , HTransformation );

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

Некоторые (устаревшие) средства разработки, выдают всплывающие подсказки по функциям с учетом подстановки всех typedef, т.е. подскажут пользователю transformTexture(void*, void*) и он будет вынужден, каждый раз, смотреть документацию, вместо использования подсказок.

При применении функционального подхода, т.е., например, при автоматическом генерировании функций по прототипу:

template< typename FunctionPtr >
FunctionPtr applayLogger( FunctionPtr );
auto loggedTransformTexture = applayLogger( &transformTexture );

В подсказках к loggedTransformTexture информация о типах, в лучшем случае, будет приведена с учетом подстановки typedef, а имена аргументов будут потеряны. В тоже время информации о типах может быть достаточно.

При применении идеомы RAII, написание C++ оберток существенно упростится именно в случае отдельный типов. (Поскольку мы сможем автоматически вывести нужную функуию деструкции на основании типа, а не отслеживать историю происходения указателя.)

И наконец, если пользователь захочет написать прегруженные фкункции, принимающие аргументы разных типов. То это возможно только в случае, если типы не тождественны друг другу.

→ Ссылка