В C нет необходимости приводить void *
к любому другому типу указателя, это всегда безопасно продвигается. Однако в C ++ это не так. Например,
int *a = malloc(sizeof(int));
работает в C, но не в C ++. (Примечание: я знаю, что вам не следует использовать malloc
в C ++ или в этом отношении new
, и вместо этого следует отдавать предпочтение умным указателям и / или STL; об этом спрашивается просто из любопытства) Почему стандарт C ++ не допускает такое неявное приведение, в то время как стандарт C делает?
c++
language-features
wolfPack88
источник
источник
long *a = malloc(sizeof(int));
К сожалению, кто-то забыл изменить только один тип!sizeof(*a)
вместо этого.malloc
не может вернуть указатель на выделенный тип.new
is C ++ действительно возвращает указатель на выделенный тип, так что правильно написанному коду C ++ никогда не придется приводитьvoid *
s.void
, C сделал не . Когда это ключевое слово / идея было добавлено в C, они изменили его в соответствии с потребностями C. Это было вскоре после того, как типы указателей начали проверяться вообще . Посмотрите, можете ли вы найти в Интернете брошюру с описанием K & R C или винтажную копию программного текста на C, такого как C Primer от Waite Group . ANSI C был полон функций, перенесенных или вдохновленных C ++, а K & R C был намного проще. Поэтому более правильно, что C ++ расширил C, как он существовал в то время, а C, который вы знаете, был удален из C ++.Ответы:
Потому что неявные преобразования типов, как правило, небезопасны, и C ++ занимает более безопасную позицию при наборе текста, чем C.
C обычно допускает неявные преобразования, даже если большинство шансов, что преобразование является ошибкой. Это потому, что C предполагает, что программист точно знает, что они делают, и если нет, то это проблема программиста, а не проблема компилятора.
C ++ обычно запрещает вещи, которые потенциально могут быть ошибками, и требует, чтобы вы явно указывали свое намерение с помощью приведения типа. Это потому, что C ++ пытается быть дружественным к программисту.
Вы можете спросить: почему это так дружелюбно, когда на самом деле вам нужно печатать больше?
Итак, вы видите, что любая строка кода в любой программе, на любом языке программирования, как правило, будет прочитана намного больше, чем будет написана (*). Таким образом, легкость чтения намного важнее, чем простота написания. А при чтении выделение любых потенциально небезопасных преобразований с помощью явного приведения типов помогает понять, что происходит, и иметь определенный уровень уверенности в том, что происходящее на самом деле и должно было произойти.
Кроме того, неудобство необходимости вводить явное приведение является тривиальным по сравнению с неудобствами, которые тратятся часами на устранение неполадок, чтобы найти ошибку, которая была вызвана ошибочным назначением, о котором вы могли быть предупреждены, но никогда не были.
(*) В идеале он будет записан только один раз, но он будет читаться каждый раз, когда кому-то нужно просмотреть его, чтобы определить его пригодность для повторного использования, и каждый раз, когда происходит устранение неполадок, и каждый раз, когда кому-то нужно добавить код рядом с ним, а затем каждый раз, когда происходит поиск неисправностей в соседнем коде, и так далее. Это верно во всех случаях, за исключением сценариев «однократная запись, запуск, затем выбрасывание», и поэтому неудивительно, что большинство языков сценариев имеют синтаксис, который облегчает написание с полным пренебрежением к простоте чтения. Вы когда-нибудь думали, что Perl совершенно непостижимо? Вы не одиноки. Думайте о таких языках как о языках только для записи.
источник
void*
являются более небезопасными в C ++, потому что с тем , как некоторые особенности ООП реализованы в C ++, указатель на тот же объект может иметь различное значение в зависимости от типа указателя.Вот что говорит Страуструп :
Затем он показывает пример того, как void * может быть опасен, и говорит:
Наконец он отмечает:
Об этом он подробнее расскажет в статье «Дизайн и эволюция C ++» .
Таким образом, ответ сводится к следующему: разработчик языка считает, что это небезопасный шаблон, и поэтому сделал его незаконным и предоставил альтернативные способы выполнения того, для чего этот шаблон обычно использовался.
источник
malloc
примера, то стоит отметить, чтоmalloc
(очевидно) не будет вызывать конструктор, поэтому, если это тип класса, для которого вы выделяете память, возможность неявного приведения к типу класса может ввести в заблуждение.Это всегда рекламируется, да, но вряд ли безопасно .
C ++ отключает это поведение именно потому , что он пытается иметь более безопасную систему типов , чем C, и такое поведение не безопасно.
Рассмотрим в целом эти 3 подхода к преобразованию типов:
Что ж, 1 уродлив и является практическим препятствием для достижения чего-либо, но он может быть действительно использован там, где требуется большая осторожность. C примерно выбрал 2, который легче реализовать, и C ++ для 3, который сложнее реализовать, но безопаснее.
источник
По определению, пустой указатель может указывать на что угодно. Любой указатель может быть преобразован в пустой указатель, и, таким образом, вы сможете преобразовать обратно, получая точно такое же значение. Однако указатели на другие типы могут иметь ограничения, такие как ограничения выравнивания. Например, представьте архитектуру, в которой символы могут занимать любой адрес памяти, но целые числа должны начинаться с четных границ адреса. В некоторых архитектурах целочисленные указатели могут даже подсчитывать 16, 32 или 64 бита за раз, так что char * может фактически иметь кратное число числового значения int *, указывая на то же место в памяти. В этом случае преобразование из пустоты * фактически закруглит биты, которые не могут быть восстановлены и поэтому необратимы.
Проще говоря, указатель void может указывать на что угодно, включая вещи, на которые другие указатели могут быть не способны указывать. Таким образом, преобразование в указатель void безопасно, но не наоборот.
источник