Когда и почему указатели стали рассматриваться как рискованные?

18

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

Каковы были исторические события для этого изменения мышления? Были ли какие-то конкретные, оригинальные события, исследования или другие события?

Например, поверхностный взгляд на переход с C на C ++ на Java, кажется, показывает тенденцию дополнять, а затем полностью заменять указатели ссылками. Однако настоящая цепочка событий была, вероятно, гораздо более тонкой и сложной, чем эта, и не настолько последовательной. Функции, которые сделали это в этих основных языках, могли появиться в другом месте, возможно, задолго до этого.

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

DaveInCaz
источник
1
Это было связано с падением образования гуманитарных наук. Люди больше не могли постигать Indirect Reference, одну из самых фундаментальных идей в вычислительной технике, включенную во все процессоры.
10
Указатели являются рискованными. Как вы думаете, почему произошел сдвиг в мышлении? Были улучшены языковые функции и аппаратные средства, которые позволяют писать программное обеспечение без указателей, хотя и не без некоторого снижения производительности.
Прекратить причинять вред Монике
4
@DaveInCaz Насколько я знаю, особой разработкой было изобретение указателей.
Прекратить причинять вред Монике
5
@nocomprende: то, что вы только что написали, - это не факты и не доказательства, а мнение. В 1970 году было гораздо меньше программистов, и у вас нет никаких доказательств того, что население сегодня лучше или хуже при «косвенном обращении».
whatsisname
3
Указатели всегда считались рискованными с самого первого дня. Это был просто компромисс, чтобы перевести их с ассемблера на языки более высокого уровня.
Фрэнк Хайлеман,

Ответы:

21

Обоснованием была разработка альтернатив указателям.

Под капотом любой указатель / ссылка / и т. Д. Реализуется как целое число, содержащее адрес памяти (или указатель). Когда вышел C , эта функциональность была представлена ​​как указатели. Это означало, что все, что может сделать базовое оборудование для адресации памяти, может быть сделано с помощью указателей.

Это всегда было «опасно», но опасность относительна. Когда вы создаете программу из 1000 строк или когда у вас есть процедуры обеспечения качества программного обеспечения IBM, эта опасность может быть легко устранена. Однако не все программное обеспечение разрабатывалось таким образом. Таким образом, возникла потребность в более простых структурах.

Если вы думаете об этом, a int&и a int* constдействительно имеют один и тот же уровень безопасности, но один из них имеет более приятный синтаксис, чем другой. int&также может быть более эффективным, поскольку он может ссылаться на int, хранящийся в регистре (анахронизм: это было верно в прошлом, но современные компиляторы настолько хороши в оптимизации, что вы можете иметь указатель на целое число в регистре, пока Вы никогда не используете какие-либо функции, которые требуют фактического адреса, например ++)

Когда мы переходим на Java , мы переходим на языки, которые предоставляют некоторые гарантии безопасности. C и C ++ не предоставили ни одного. Java гарантирует, что выполняются только легальные операции. Чтобы сделать это, Java полностью покончил с указателями. Они обнаружили, что подавляющее большинство операций указателя / ссылки, выполняемых в реальном коде, были вещами, для которых ссылок было более чем достаточно. Только в нескольких случаях (таких как быстрая итерация по массиву) действительно нужны указатели. В этих случаях java получает удар во время выполнения, чтобы избежать их использования.

Этот шаг не был монотонным. C # повторно введенные указатели, хотя и в очень ограниченной форме. Они помечены как « небезопасные », что означает, что они не могут быть использованы ненадежным кодом. У них также есть явные правила относительно того, на что они могут и не могут указывать (например, просто недопустимо увеличивать указатель после конца массива). Тем не менее, они обнаружили, что было несколько случаев, когда требовалась высокая производительность указателей, поэтому они вернули их обратно.

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

Корт Аммон - Восстановить Монику
источник
3
Я не уверен, что правильно сказать, что в Java нет указателей. Я не хочу вдаваться в долгие дебаты о том, что является указателем, а что нет, но JLS говорит, что «значение ссылки является указателем». Там просто нет прямого доступа или модификации указателей. Это не только для безопасности, но и не позволяет людям отслеживать, где находится объект, в любой момент полезно для GC.
JimmyJames,
6
@JimmyJames Правда. Для целей этого ответа разделительной линией между указателем и не указателем было, поддерживает ли оно арифметические операции с указателями, которые обычно не поддерживаются ссылками.
Корт Аммон - Восстановить Монику
8
@JimmyJames Я согласен с утверждением Корта, что указатель - это то, над чем вы можете выполнять арифметические операции, а ссылка - нет. Фактический механизм, который реализует ссылку в таких языках, как Java, - это деталь реализации.
Роберт Харви,
3
В общем, C и C ++ добровольно приняли членство в этом опасном клубе, допустив множество «неопределенного поведения» в спецификации.
rwong
2
Кстати, есть в ЦПУ, отличающий между указателями и числами. Например, это делает оригинальный 48-битный процессор CISC в IBM AS / 400. И в самом деле, есть уровень абстракции под ОС, что означает , что не только центральный процессор различать между числами и указателями и упаси арифметика указателей, но сама ОС не даже не знает про указатели на все и не занимайтесь языки , Интересно, что это делает исходную систему AS / 400 единой, где переписывание кода с языка сценариев высокого уровня на C замедляет его на несколько порядков .
Йорг Миттаг
10

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

Большинство языков программирования высокого уровня (т.е. не ассемблер) достаточно безопасны для памяти и не допускают неограниченного доступа к указателю. Семья C здесь самая странная.

C развился из B, который был очень тонкой абстракцией по сравнению с необработанной сборкой. У Б был один тип: слово. Слово может быть использовано как целое число или как указатель. Эти два эквивалентны, когда вся память рассматривается как один непрерывный массив. C сохранил этот довольно гибкий подход и продолжал поддерживать небезопасную арифметику указателей. Вся система типов C - это скорее запоздалая мысль. Эта гибкость доступа к памяти сделала C очень подходящим для его основной цели: создание прототипа операционной системы Unix. Конечно, Unix и C оказались довольно популярными, так что C также используется в приложениях, где этот низкоуровневый подход к памяти на самом деле не нужен.

Если мы посмотрим на языки программирования, которые были до C (например, диалекты Fortran, Algol, включая Pascal, Cobol, Lisp, ...), то некоторые из них поддерживают указатели, подобные C. Примечательно, что концепция нулевого указателя была изобретена для Algol W в 1965 году. Но ни один из этих языков не пытался быть C-подобным, эффективным языком систем с низкой абстракцией: Fortran предназначался для научных вычислений, Algol разработал несколько довольно продвинутых концепций, Lisp был больше исследовательский проект, чем язык промышленного уровня, и Cobol был сосредоточен на бизнес-приложениях.

Сбор мусора существовал с конца 50-х годов, то есть задолго до C (начала 70-х). Для правильной работы GC требуется безопасность памяти. Языки до и после C использовали GC как обычную функцию. Конечно, это делает язык намного сложнее и, возможно, медленнее, что было особенно заметно во времена мэйнфреймов. Языки GC, как правило, ориентированы на исследования (например, Lisp, Simula, ML) и / или требуют мощных рабочих станций (например, Smalltalk).

С меньшими, более мощными компьютерами вычисления в целом и языки GC, в частности, стали более популярными. Для приложений не в реальном времени (а иногда даже тогда) GC сейчас является предпочтительным подходом. Но алгоритмы GC также были предметом интенсивных исследований. В качестве альтернативы улучшена безопасность памяти без GC, особенно в последние три десятилетия: заметными нововведениями являются RAII и интеллектуальные указатели в C ++ и средство проверки системы / заимствования Rust.

Java не вводила новшеств, будучи безопасным для памяти языком программирования: она в основном брала семантику GCed, безопасного языка памяти Smalltalk, и сочетала их с синтаксисом и статической типизацией C ++. Затем он продавался как лучший, более простой C / C ++. Но это только внешне потомок C ++. Отсутствие указателей в Java во многом связано с объектной моделью Smalltalk, а не с отказом от модели данных C ++.

Таким образом, «современные» языки, такие как Java, Ruby и C #, не должны интерпретироваться как преодоление проблем необработанных указателей, таких как C, но должны рассматриваться как основанные на многих традициях - включая C, но также и на более безопасных языках, таких как Smalltalk, Simula, или Лисп.

Амон
источник
4

По моему опыту, указатели ВСЕГДА были сложной концепцией для многих людей. В 1970 году в университете, в котором я учился, был Burroughs B5500, и мы использовали Extended Algol для наших программных проектов. Аппаратная архитектура была основана на дескрипторах и некоторых кодах в верхней части слов данных. Они были специально разработаны, чтобы массивы могли использовать указатели, не допуская, чтобы они уходили с конца.

Мы провели оживленную дискуссию в классе о справочнике «имя против значения» и о том, как работают массивы B5500. Некоторые из нас получили объяснение немедленно. Другие не сделали.

Позже, это было несколько шокирующим, что аппаратное обеспечение не защитило меня от неуправляемых указателей - особенно на языке ассемблера. На моей первой работе после окончания учебы я помог исправить проблемы в операционной системе. Часто единственной документацией, которую мы имели, была распечатанная аварийная свалка. Я разработал умение находить источники неуправляемых указателей в дампах памяти, поэтому каждый дал мне «невозможные» дампы, чтобы разобраться. Больше проблем, которые мы имели, были вызваны ошибками указателя, чем любой другой тип ошибки.

Многие из тех, с кем я работал, начали писать на Фортране, затем перешли на С, написали на С, который очень похож на Фортран, и избегали указателей. Поскольку они никогда не усваивают указатели и ссылки, Java создает проблемы. Часто программистам на Фортране сложно понять, как на самом деле работает назначение объектов.

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

Валери Гриффин
источник