Являются ли ref и out в C # одинаковыми указателями a в C ++?

StackOverflow https://stackoverflow.com/questions/1167342

Вопрос

Я только что создал процедуру подкачки в 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".

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top