В чем разница между ссылкой на C# и указателем?
Я не совсем понимаю разницу между ссылкой на C# и указателем. Они оба указывают на место в памяти, не так ли? Единственное различие, которое я могу понять, заключается в том, что указатели не так умны, не могут указывать на что-либо в куче, освобождаются от сборки мусора и могут ссылаться только на структуры или базовые типы.
одна из причин, по которой я спрашиваю, заключается в том, что существует мнение, что люди должны хорошо понимать указатели (от C, я думаю), чтобы быть хорошим программистом. Много люди, которые изучают языки более высокого уровня, упускают это и поэтому имеют эту слабость.
Я просто не понимаю, что такого сложного в указателе? Это просто ссылка на место в памяти, не так ли? Он может вернуть свое местоположение и взаимодействовать с объектом в этом месте напрямую?
Я пропустил массивный момент?
10 ответов:
ссылки на C# могут и будут перемещены сборщиком мусора, но обычные указатели статичны. Вот почему мы используем
fixedключевое слово при получении указателя на элемент массива, чтобы предотвратить его перемещение.EDIT: концептуально, да. Они более или менее одинаковы.
существует небольшое, но чрезвычайно важное различие между указателем и ссылкой. Указатель на место в памяти, а ссылка указывает на объект в памяти. Указатели не являются "типобезопасными" в том смысле, что вы не можете гарантировать правильность памяти, на которую они указывают.
возьмем для примера следующий код
int* p1 = GetAPointer();это типобезопасно в том смысле, что GetAPointer должен возвращать тип, совместимый с int*. Пока еще нет гарантируйте, что *p1 будет фактически указывать на int. Это может быть символ, двойной или просто указатель в случайную память.
однако ссылка указывает на конкретный объект. Объекты могут быть перемещены в памяти, но ссылка не может быть признана недействительной (если вы не используете небезопасный код). Ссылки в этом отношении гораздо безопаснее, чем указатели.
string str = GetAString();в этом случае str имеет одно из двух состояний 1) он указывает на отсутствие объекта и, следовательно, null или 2) он указывает на допустимую строку. Вот и все. Среда CLR гарантирует, что это так. Он не может и не будет для указателя.
ссылка-это "абстрактный" указатель: вы не можете делать арифметику со ссылкой, и вы не можете играть в какие-либо низкоуровневые трюки с ее значением.
сначала я думаю, что вам нужно определить "указатель" в вашей сематике. Вы имеете в виду указатель, который вы можете создать в небезопасном коде с помощью основные? Вы имеете в виду IntPtr что вы получаете от возможно родного звонка или Маршал.AllocHGlobal? Вы имеете в виду GCHandle? Все они по существу одно и то же - представление адреса памяти, где что-то хранится-будь то класс, число, структура, что угодно. И для протокола, они конечно, может быть на куче.
указатель (все вышеперечисленные версии) является фиксированным элементом. GC понятия не имеет, что находится по этому адресу, и поэтому не имеет возможности управлять памятью или жизнью объекта. Это означает, что вы теряете все преимущества системы сбора мусора. Вы должны вручную управлять памятью объекта, и у вас есть потенциал для утечек.
ссылка, с другой стороны, в значительной степени является "управляемым указателем", о котором знает GC. Это все-таки адрес объекта, но теперь GC знает детали цели, поэтому он может перемещать ее, выполнять уплотнения, завершать, утилизировать и все другие приятные вещи, которые делает управляемая среда.
основная разница, действительно, в том, как и почему вы будете их использовать. В подавляющем большинстве случаев в управляемом языке вы будете использовать ссылку на объект. Указатели становятся удобными для выполнения взаимодействия и редкой потребности в действительно быстрой работе.
Edit: на самом деле вот хороший пример когда вы можете использовать "указатель" в управляемом коде - в этом случае это GCHandle, но то же самое можно было бы сделать с AllocHGlobal или с помощью фиксированного массива байтов или структуры. Я предпочитаю GCHandle, потому что он чувствует себя более ".NET" для меня.
указатели указывают на местоположение в адресном пространстве памяти. Ссылки указывают на структуру данных. Структуры данных все время перемещаются (ну, не так часто, но время от времени) сборщиком мусора (для уплотнения пространства памяти). Также, как вы сказали, структуры данных без ссылок будут собирать мусор через некоторое время.
кроме того, указатели можно использовать только в небезопасном контексте.
Я думаю, что это важно для разработчиков, чтобы понять концепция указатель-то есть, чтобы понять косвенность. Это не означает, что они обязательно должны использовать указатели. Также важно понимать, что
указатель может указывать на любой байт в адресном пространстве приложения. Ссылка жестко ограничена и контролируется и управляется средой .NET.
null или же определить объект его надлежащего типа.
обратите внимание, что каждая ссылка на объект фактически инкапсулирует два вида информация: (1) содержимое поля объекта, который он идентифицирует, и (2) набор других ссылок на тот же объект. Хотя нет никакого механизма, с помощью которого система может быстро идентифицировать все ссылки, которые существуют на объект, набор других ссылок, которые существуют на объект, часто может быть самой важной вещью, инкапсулированной ссылкой (Это особенно верно, когда вещи типа
Objectиспользуются как такие вещи, как токены блокировки). Хотя система хранит несколько бит данные для каждого объекта для использования вGetHashCode, объекты не имеют реальной идентичности за пределами набора ссылок, которые существуют для них. ЕслиXсодержит единственную сохранившуюся ссылку на объект, заменяяXсо ссылкой на новый объект с тем же содержанием поля не будет иметь никакого идентифицируемого эффекта, кроме как изменить биты, возвращаемыеGetHashCode()и даже этот эффект не гарантируется.
дело в указателях, которые делают их несколько сложными, - это не то, что они есть, а то, что вы можете с ними сделать. И когда у вас есть указатель на указатель на указатель. Вот когда он действительно начнет получать удовольствие.
одним из самых больших преимуществ ссылок над указателями является большая простота и читаемость. Как всегда, когда вы упрощаете что-то, вы упрощаете его использование, но за счет гибкости и контроля вы получаете материал низкого уровня (как уже упоминали другие люди).
указатели часто критикуют за то, что некрасивый.
class* myClass = new class();Теперь каждый раз, когда вы используете его, вы должны разыменовать его сначала либо
myClass->Method() or (*myClass).Method()несмотря на потерю некоторой читаемости и добавляя сложность, люди все еще должны были часто использовать указатели в качестве параметров, чтобы вы могли изменять фактический объект (вместо передачи по значению) и для повышения производительности не нужно было копировать огромные объекты.
для меня именно поэтому ссылки были "рождены" в первую очередь, чтобы обеспечить ту же выгоду, что и указатели, но без всего этого синтаксиса указателя. Теперь вы можете передать фактический объект (а не только его значение), и у вас есть более читаемый, нормальный способ взаимодействия с объект.
MyMethod(&type parameter) { parameter.DoThis() parameter.DoThat() }ссылки на C++ отличались от ссылок на C# / Java тем, что как только вы назначаете ему значение, которое было им, вы не можете повторно назначить его (и он должен быть назначен, когда он был объявлен). Это было то же самое, что использовать указатель const (указатель, который не может быть повторно указан на другой объект).
Java и C# - это очень высокий уровень, современные языки, которые очистили много беспорядков, накопившихся в C / C++ за эти годы, и указатели были определенно одним из тех вещей, которые нужно было "очистить".
насколько ваш комментарий о знании указателей делает вас более сильным программистом, это верно в большинстве случаев. Если вы знаете " как " что-то работает, а не просто использовать его, не зная, я бы сказал, что это часто может дать вам преимущество. Сколько края всегда будет меняться. В конце концов, использование чего-то, не зная, как это реализовано, является одной из многих красот ООП и интерфейсов.
В этом конкретном примере, что может ли знание указателей помочь вам со ссылками? Понимание того, что ссылка на C# не является самим объектом, а указывает на объект, является очень важным понятием.
#1: Вы не проходите по значению Ну для начала, когда вы используете указатель, вы знаете, что указатель содержит адрес, вот и все. Сама переменная почти пуста, и поэтому ее так приятно передавать в качестве аргументов. В дополнение к увеличению производительности, вы работаете с фактическим объектом поэтому любые изменения, которые вы делаете, не являются временными
#2: Полиморфизм / Интерфейсы Если у вас есть ссылка, которая является типом интерфейса и указывает на объект, вы можете вызывать только методы этого интерфейса, даже если объект может иметь гораздо больше возможностей. Объекты также могут реализовывать одни и те же методы по-разному.
Если вы хорошо понимаете эти понятия, то я не думаю, что вы слишком много упускаете из-за того, что не использовали указатели. C++ часто используется в качестве язык для изучения программирования, потому что это хорошо, чтобы получить ваши руки грязные иногда. Кроме того, работа с аспектами более низкого уровня заставляет вас ценить комфорт современного языка. Я начал с C++ и теперь программист C#, и я чувствую, что работа с необработанными указателями помогла мне лучше понять, что происходит под капотом.
Я не думаю, что это необходимо для всех, чтобы начать с указателей, но важно то, что они понимают, почему ссылки используется вместо value-типов и лучший способ понять это-посмотреть на своего предка, указатель.
Comments