Преобразование в void * и обратно в Original_Data_Type *

Я видел и использовал это много раз в C ++, особенно в различных реализациях потоков. Что мне интересно, есть ли какие-либо подводные камни / проблемы с этим? Есть ли какой-нибудь способ, которым мы могли бы столкнуться с ошибкой или неопределенным состоянием, когда мы приводим к void * и обратно? Как мы должны решить такие проблемы, если они есть?

Спасибо.

0

Решение

Что мне интересно, есть ли какие-либо подводные камни / проблемы с этим?

Вы должны быть абсолютно уверены во время void* вернуться к конкретному типу, если вы этого не сделаете, вы получите Неопределенное поведение и потенциальная катастрофа. Как только вы используете void * ты проиграл тип безопасности.Сложно отследить, какого типа void * на самом деле указывает на то, что нет способа гарантировать или определить, что он действительно указывает на тип, к которому вы собираетесь привести его обратно.

Есть ли какой-нибудь способ, которым мы могли бы столкнуться с ошибкой или неопределенным состоянием, когда мы приводим к void * и обратно?

Да, сценарий, упомянутый в #1,

Как мы должны решить такие проблемы, если они есть?

Избегать использования void * в C ++ полностью, вместо этого используйте шаблоны и наследование.
В Си вам может понадобиться это в определенных ситуациях, но постарайтесь свести его использование к минимуму.
Нижняя линия,
C / C ++ позволяет вам выстрелить себе в ногу, решать вам или нет.

2

Другие решения

я имею не Видно, что в C ++ много разыгрывается. Это была практика в C, которую активно избегали в C ++.

Приведение к пустоте * удаляет все типы безопасности.

Если вы используете reinterpret_cast или же static_cast привести от типа указателя к void* и вернуться к тому же типу указателя, на самом деле стандарт гарантирует, что результат будет четко определен.

Опасность в том, что вы можете разыграть void* к неправильному типу, так как вы больше не уверены, какой был правильный тип.

3

Я знаю много функций в драйвере и т. Д., Использующих указатели void для возврата данных вызывающей стороне, схема в основном такая же:

int requestSomeData(int kindOfData, void * buffer, int bufferSize);

Эта функция может принимать разные типы данных в качестве параметра.
Что они делают, так это используют bufferSize в качестве параметра, чтобы избежать записи в места памяти, в которые они не должны писать.
Если bufferSize не совпадает или меньше, чем данные, которые должны быть возвращены, функция возвратит код ошибки.

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

1

Единственное, что стандартные гранты это то, что, учитывая A* pa, (A*)(void*)pA == pA,
Следствие

void* pv = pA;
A* pA2 = (A*)pv;
pA2->anything ...

будет так же, как pA->anything ...

Все остальное «не определено», фактически — как-то зависит от реализации.

Исходя из моего опыта, вот некоторые известные подводные камни:

  • Рассматривать A производная форма B, pA а также pB быть A* а также B*, pB=pA марки pB указать на основание A, Это не значит, что pB а также pA один и тот же адрес. следовательно pB = (B*)(void*)pA на самом деле может указывать куда-либо еще на A (хотя объекты с единым наследованием обычно реализуются с одним и тем же источником, поэтому, очевидно, работает нормально)
  • То же самое и наоборот: если предположить pB на самом деле указывает на A, pA = (A*)(void*)pB не обязательно указывать правильно на объект. Правильный путь pA = static_cast<A*>(pB);
  • Если вышеупомянутые пункты могут работать с большинством реализаций с единым наследованием, никогда не будет работать с множественным наследованием для основ, отличных от первого: class A: public Z, public B { ... }; если Z не пусто, учитывая A, B субкомпонент не будет иметь тот же адрес. (и множественное наследование в C ++ везде, где есть iostream)
  • Иногда все зависит и от платформы: (char*)(void*)pI (где pI указывает на целое число) не будет таким же, как «*pI если *pI в (-128 .. + 127) «(это будет только на машинах с прямым порядком байтов)

В общем не предполагайте, что преобразование между типами работает, просто меняя способ интерпретации адреса.

1
По вопросам рекламы [email protected]