Являются ли ref и out в C # одинаковыми указателями a в C ++?
Вопрос
Я только что создал процедуру подкачки в C # следующим образом:
static void Swap(ref int x, ref int y)
{
int temp = x;
x = y;
y = temp;
}
Он делает то же самое, что и этот код на C ++:
void swap(int *d1, int *d2)
{
int temp=*d1;
*d1=*d2;
*d2=temp;
}
Так же как и ref
и out
ключевые слова, такие как указатели для C #, без использования unsafe
код?
Решение
Они более ограничены.Вы можете сказать ++ для указателя, но не для ref
или out
.
Редактировать Некоторая путаница в комментариях, так что для полной ясности:смысл здесь в том, чтобы сравнить с возможностями указателей.Вы не можете выполнить ту же операцию, что и ptr++
на ref
/out
, т. е.сделайте так, чтобы он адресовался к соседнему местоположению в памяти.Это правда (но здесь неуместно), что вы можете выполнить эквивалент (*ptr)++
, но это означало бы сравнить его с возможностями ценности, а не указатели.
Можно с уверенностью сказать, что внутренне они являются просто указателями, потому что стек не перемещается, а C # тщательно организован так, чтобы ref
и out
всегда обращайтесь к активной области стека.
Редактировать Чтобы еще раз внести абсолютную ясность (если это еще не было ясно из приведенного ниже примера), суть здесь не в том, что ref
/out
может Только укажите на стек.Дело в том, что когда он указывает на стек, правила языка гарантируют, что он не превратится в висячий указатель.Эта гарантия необходима (и здесь уместна / интересна), потому что стек просто отбрасывает информацию в соответствии с завершением вызова метода, без каких-либо проверок, чтобы убедиться, что какие-либо рефереры все еще существуют.
И наоборот , когда ref
/out
ссылается на объекты в куче GC неудивительно, что эти объекты могут поддерживаться в рабочем состоянии столько, сколько необходимо:куча GC предназначена именно для того, чтобы сохранять объекты в течение любого периода времени, требуемого их реферерами, и обеспечивает закрепление (см. Пример ниже) для поддержки ситуаций, когда объект не должен быть перемещен путем сжатия GC.
Если вы когда-нибудь поиграете с interop в небезопасном коде, вы обнаружите, что ref
очень тесно связан с указателями.Например, если COM-интерфейс объявлен следующим образом:
HRESULT Write(BYTE *pBuffer, UINT size);
Сборка взаимодействия превратит это в это:
void Write(ref byte pBuffer, uint size);
И вы можете сделать это, чтобы вызвать его (я полагаю, что материал COM-взаимодействия заботится о закреплении массива):
byte[] b = new byte[1000];
obj.Write(ref b[0], b.Length);
Другими словами, ref
к первому байту вы получаете доступ ко всему этому;по-видимому, это указатель на первый байт.
Другие советы
Ссылочные параметры в C # могут быть использованы для замены один использование указателей, да.Но не все.
Другое распространенное применение указателей - это средство для перебора по массиву.Параметры Out / ref не могут этого сделать, так что нет, они не "совпадают с указателями".
ref
и out
используются только с аргументами функции для обозначения того, что аргумент должен передаваться по ссылке, а не по значению.В этом смысле, да, они чем-то похожи на указатели в C ++ (на самом деле больше похожи на ссылки).Подробнее об этом читайте в эта статья.
На самом деле, я бы сравнил их со ссылками на C ++, а не с указателями.Указатели в C ++ и C являются более общим понятием, и ссылки будут делать то, что вы хотите.
Все это, несомненно, подсказки под прикрытием, конечно.
Приятная вещь в использовании вон заключается в том, что вы гарантируете, что элементу будет присвоено значение - в противном случае вы получите ошибку компиляции.
Пока сравнения в глазах смотрящего...Я говорю "нет".'ref' изменяет соглашение о вызове но не тот Тип из параметров.В вашем примере C ++ d1 и d2 имеют тип int * .В C # они по-прежнему являются Int32, просто так получилось, что они передаются по ссылке, а не по значению.
Кстати, ваш код на C ++ на самом деле не меняет местами свои входные данные в традиционном смысле.Обобщая это следующим образом:
template<typename T>
void swap(T *d1, T *d2)
{
T temp = *d1;
*d1 = *d2;
*d2 = temp;
}
...не будет работать до тех пор, пока все типы T не будут иметь конструкторов копирования, и даже тогда это будет гораздо более неэффективно, чем замена указателей.
Короткий ответ - Да (аналогичная функциональность, но не совсем тот же механизм).В качестве дополнительного примечания, если вы используете FxCop для анализа вашего кода, используя out
и ref
приведет к ошибке "Microsoft.Дизайн" типа "CA1045:DoNotPassTypesByReference".