Как ссылка отличается от указателя в реализации? [дубликат]

Возможный дубликат:
Различие между переменной указателя и ссылочной переменной в C++

Я читаю о книге "В Модели Объекта C++" Stanley Lippman. То, что озадачивает меня, является различием между "ссылкой" объекта и "указателем" на объект. Я знаю, что ссылка должна быть инициализирована при объявлении, в то время как указатель мог быть оставлен для более поздней инициализации. Но я хочу знать физическое различие в реализации между ними.

Почему должен там быть "ссылочный" механизм; разве это не перекрывающий функцию указателя? Под каким обстоятельством мы должны использовать ссылку кроме указателя?Большое спасибо.

28
задан Community 23 May 2017 в 12:33
поделиться

9 ответов

Большинство ссылок реализовано с использованием переменной-указателя, т.е. ссылка обычно занимает одно слово памяти. Однако ссылка, которая используется исключительно локально, может - и часто удаляется - оптимизатором . Например:

  struct S { int a, int b[100]; };  
  void do_something(const vector<S>& v)
  {
    for (int i=0; i<v.size(); ++i) {
        int*& p = v[i].b;
          for (int j=0; j<100; ++j) cout <<p[j];
  }

В этом случае p не нужно хранить в памяти (возможно, он просто существует в регистре, может быть, он исчезнет в инструкциях).

8
ответ дан 28 November 2019 в 03:48
поделиться

Если бы imagestr был растровыми данными (а мы теперь знаем, что это не так), можно было бы использовать следующее

imagestr - строка в кодировке base64
width - ширина изображения
height - высота изображения

from PIL import Image
from base64 import decodestring

image = Image.fromstring('RGB',(width,height),decodestring(imagestr))
image.save("foo.png")

Поскольку imagestr - это просто закодированные данные png

from base64 import decodestring

with open("foo.png","wb") as f:
    f.write(decodestring(imagestr))
-. 121---804114-

Ссылку можно рассматривать как неявно отнесенный к константе указатель (обратите на это внимание). Один раз ссылка, всегда ссылка. Это позволяет упростить написание кода. Если, конечно, вы не введете семантику перемещения и r-значения ссылок. Стандарт не предписывает, как должны быть реализованы ссылки, точно так же, как он не предписывает, как должны быть реализованы указатели. Однако в большинстве случаев указатели являются синонимом адресов объектов.

9
ответ дан 28 November 2019 в 03:48
поделиться

Используйте ссылки, когда можете, и указатели, когда вам нужно. Причины, по которым вам потребуется использовать указатель:

  1. Может не быть объекта, на который он мог бы указывать (нулевой указатель, нет нулевых ссылок).
  2. Вам может понадобиться ссылаться на разные объекты в течение его жизни.
  3. Возможно, вам потребуется обратиться к целому массиву объектов (но обычно лучше std :: vector ).

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

template <class T, size_t N>
size_t size(T(&matrix)[N]) {
    return N;
}

Это позволяет вам определить размер массива:

int array1[some_size];
int array2[some_other_size];

size_t n = size(array1);  // retrieves `some_size`
size_t m = size(array2);  // retrieves `some_other_size`

... но он просто не будет компилироваться, если вы попытаетесь передать ему указатель:

int *x = new int[some_size];

size_t n = size(x);    // won't compile

В лучшем случае, кажется, не имеет смысла писать код для получения указателя, когда его целью является отклонение передачи указателя.

6
ответ дан 28 November 2019 в 03:48
поделиться

Ссылки в большинстве случаев являются внутренними указателями (особенно при хранении или передаче в функции). Они работают так же, как и указатели, при условии, что используются только операции, допустимые для обоих.

Дополнительные проверки и синтаксический сахар для ссылок являются исключительно функцией времени компиляции, как и система типов (большая часть информации о типах данных теряется во время компиляции).

Важными отличиями являются

  • Ссылка всегда указывает на объект (не может быть NULL)
  • Ссылка указывает только на один объект (не на массив, как это может делать указатель)
  • Ссылка должна быть инициализирована изначально (иначе вы получите ошибку компиляции)
  • Ссылка не может быть изменена после инициализации, чтобы указывать на что-то другое
  • Удаление объекта, на который указывает ссылка, в то время как переменная ссылки остается живой, является неопределенным поведением (но не ошибкой компиляции)
2
ответ дан 28 November 2019 в 03:48
поделиться

Ссылки C ++ в значительной степени являются синтаксическим механизмом.

Рассмотрим

int x;
int &y = x;
int *z = &x;

Выражение (* z) то же самое, что (y).

Помимо экономии ввода нескольких символов, единственное, что здесь происходит, это то, что as reference не может быть нулевым.

0
ответ дан 28 November 2019 в 03:48
поделиться

Указатель - это отдельное значение, не зависящее от данных, на которые он указывает. (Число 0x12345678 имеет смысл как значение указателя, даже если в памяти нет значимых данных по адресу 0x12345678). Поскольку это отдельное значение, им можно манипулировать самостоятельно: его можно увеличивать или уменьшать, сравнивать с другими указателями и выводить его значение на экран, независимо от того, "указывает ли оно на что-либо"

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

Возможно, это правда, что ссылки обычно преобразуются в указатели в скомпилированном машинном коде, но вы должны думать об этом как о частной детали реализации компилятора, а не как о гарантии. Ссылки - это собственная концепция с собственными случаями использования, а не просто другой способ работы с указателями.

Когда вам нужно отдельное значение, подобное указателю, которым вы можете манипулировать и исследовать независимо от данных, на которые оно указывает, используйте указатель (или, лучше всего, класс smart-pointer). Когда вам нужен способ взять значение, существующее в одной области видимости, и сделать его доступным в другой области видимости (например, передать объект в функцию без его копирования), используйте ссылку.

1
ответ дан 28 November 2019 в 03:48
поделиться

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

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

0
ответ дан 28 November 2019 в 03:48
поделиться

Один из примеров, когда вместо указателей следует использовать ссылки:

enum day
{
    Mon, Tue, Wed, Thu, Fri, Sat, Sun
};

day d;

day *operator++(day *d);

Оператор ++ можно вызвать с помощью ++&d, что не выглядит интуитивно понятным.

Одна большая загвоздка здесь заключается в том, что все перегруженные функции-операторы должны либо быть членами класса, либо иметь параметр типа T, T &, или T const &, где T - это класс или тип перечисления. Таким образом, в данном случае day *operator++(day *d); даже не скомпилируется.

Он прекрасно работает при использовании ссылки, т.е.

day &operator++(day &d);

которая может быть вызвана просто как ++d;

Вот хорошая статья, откуда я взял этот пример.

cheers

0
ответ дан 28 November 2019 в 03:48
поделиться

Ссылки - это замаскированные указатели, или, по крайней мере, это безопасный способ думать о них.

Одна из причин для них заключается в том, что C и C ++ не имеют параметров "var", как в Паскале и т. Д. Использование ссылки дает вам нечто очень близкое к этому, но в отличие от "var", ее также можно использовать в другом месте - например чтобы дать вам краткое обозначение чего-то еще ...

int& alias = thing.blah [foo]->bar;
handle (alias, alias+1, alias*2);

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

std::deque<int>  mydeque;
mydeque.push_back (1);
mydeque.back () += 1;  //  increment the top item on the stack

Та же функциональность может быть достигнута с помощью указателя, но ссылка более удобна. Обычный термин - « синтаксический сахар ».

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

1
ответ дан 28 November 2019 в 03:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: