Подтвердить что ты не робот

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

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

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

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

4b9b3361

Ответ 1

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

  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 не нужно хранить в памяти (возможно, он существует только в регистре, возможно, он исчезает в инструкциях).

Ответ 2

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

Ответ 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

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

Ответ 4

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

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

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

  • Ссылка всегда указывает на объект (не может быть NULL)
  • Ссылка указывает только на один объект (не на такой массив, как указатель)
  • Ссылка должна быть инициализирована изначально (иначе вы получите ошибку компиляции)
  • Ссылка не может быть изменена после инициализации, чтобы указать где-то в другом месте
  • Удаление объекта, на которое указывает ссылка, в то время как ссылочная переменная остается в живых, Undefined Поведение (но не ошибка компиляции)

Ответ 5

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

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

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

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

Ответ 6

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

Одной из причин для них является то, что у C и С++ нет параметров "var", как в Pascal и т.д. Использование ссылки дает вам нечто очень близкое к этому, но в отличие от "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

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

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

Ответ 7

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

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

Ответ 8

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

Рассмотрим

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

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

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

Ответ 9

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

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); даже не будет компилироваться.

Он отлично работает, используя ссылку i.e.

day &operator++(day &d);

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

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

веселит