c ++ указатели и ссылки [дубликат]

Используйте establish_connection для переключения в другую базу данных:

ActiveRecord::Base.establish_connection(
  :adapter  => "mysql",
  :host     => "localhost",
  :username => "myuser",
  :password => "mypass",
  :database => "somedatabase"
)

Вы также можете передать предварительно сконфигурированную среду из database.yml следующим образом:

ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['other_env'])

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

MyClass.establish_connection(...)

2633
задан metamorphosis 17 June 2018 в 05:34
поделиться

24 ответа

  1. Указатель можно переназначить:
    int x = 5;
    int y = 6;
    int *p;
    p =  &x;
    p = &y;
    *p = 10;
    assert(x == 5);
    assert(y == 10);
    
    Ссылка не может быть назначена и должна быть назначена при инициализации:
    int x = 5;
    int y = 6;
    int &r = x;
    
  2. Указатель имеет свой собственный адрес и размер памяти в стеке (4 байта на x86), тогда как ссылка имеет один и тот же адрес памяти (с исходной переменной), но также занимает некоторое место в стеке. Поскольку ссылка имеет тот же адрес, что и исходная переменная, безопасно думать о ссылке как о другом имени для той же переменной. Примечание. То, на что указывает указатель, может быть в стеке или в куче. То же ссылка. Моя претензия в этом утверждении заключается не в том, что указатель должен указывать на стек. Указатель - это просто переменная, содержащая адрес памяти. Эта переменная находится в стеке. Поскольку ссылка имеет свое собственное пространство в стеке, а так как адрес совпадает с переменной, которую он ссылается. Подробнее о стеке против кучи . Это означает, что существует реальный адрес ссылки, который компилятор вам не скажет.
    int x = 0;
    int &r = x;
    int *p = &x;
    int *p2 = &r;
    assert(p == p2);
    
  3. У вас могут быть указатели на указатели на указатели, предлагающие дополнительные уровни косвенности. В то время как ссылки предлагают только один уровень косвенности.
    int x = 0;
    int y = 0;
    int *p = &x;
    int *q = &y;
    int **pp = &p;
    pp = &q;//*pp = q
    **pp = 4;
    assert(y == 4);
    assert(x == 0);
    
  4. Указателю можно назначить nullptr напрямую, тогда как ссылка не может. Если вы достаточно стараетесь, и знаете, как это сделать, вы можете сделать адрес ссылки nullptr. Аналогично, если вы достаточно стараетесь, вы можете иметь ссылку на указатель, а затем эта ссылка может содержать nullptr.
    int *p = nullptr;
    int &r = nullptr; <--- compiling error
    int &r = *p;  <--- likely no compiling error, especially if the nullptr is hidden behind a function call, yet it refers to a non-existent int at address 0
    
  5. Указатели могут выполнять итерацию по массиву, вы можете использовать ++, чтобы перейти к следующему элементу, на который указывает указатель, и + 4, чтобы перейти к 5-му элементу. Это независимо от того, какой размер указывает объект, на который указывает указатель.
  6. Указатель должен быть разыменован *, чтобы получить доступ к адресу памяти, на которое он указывает, тогда как ссылку можно использовать напрямую. Указатель на класс / структура использует -> для доступа к своим членам, тогда как ссылка использует ..
  7. Указатель - это переменная, которая содержит адрес памяти. Независимо от того, как выполняется эта ссылка, ссылка имеет тот же адрес памяти, что и элемент, который он ссылается.
  8. Ссылки не могут быть заполнены в массив, тогда как указатели могут быть (указано пользователем @litb)
  9. Ссылки на Const могут быть привязаны к временным. Указатели не могут (не без какой-либо косвенности):
    const int &x = int(12); //legal C++
    int *y = &int(12); //illegal to dereference a temporary.
    
    Это делает const& более безопасным для использования в списках аргументов и т. Д.
1379
ответ дан 21 revs, 9 users 57% 15 August 2018 в 23:13
поделиться
  • 1
    ... но разыменование NULL не определено. Например, вы не можете проверить, является ли ссылка NULL (например, & amp; ref == NULL). – Pat Notz 11 September 2008 в 23:07
  • 2
    Число 2 не истинно. Ссылки - это не просто «другое имя для одной и той же переменной». Ссылки могут быть переданы функциям, хранящимся в классах и т. Д. Способом, очень похожим на указатели. Они существуют независимо от переменных, на которые они указывают. – Derek Park 13 September 2008 в 00:37
  • 3
    Брайан, стек не имеет значения. Ссылки и указатели не должны занимать место в стеке. Они могут быть выделены в кучу. – Derek Park 19 September 2008 в 05:33
  • 4
    Брайан, тот факт, что переменная (в данном случае указатель или ссылка) требует пространства, делает not означает, что для стека требуется пространство. Указатели и ссылки могут не только point в кучу, они могут быть выделены в куче. – Derek Park 19 September 2008 в 16:26
  • 5
    другой важный diff: ссылки не могут быть заполнены в массив – Johannes Schaub - litb 27 February 2009 в 22:10

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

void increment(int *ptrint) { (*ptrint)++; }
void increment(int &refint) { refint++; }
void incptrtest()
{
    int testptr=0;
    increment(&testptr);
}
void increftest()
{
    int testref=0;
    increment(testref);
}

Многие компиляторы при встраивании указателя версии один на самом деле вынуждают запись в память (мы берем адрес явно). Тем не менее, они оставят ссылку в регистре, который является более оптимальным.

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

8
ответ дан Adisak 15 August 2018 в 23:13
поделиться

Существует одно фундаментальное различие между указателями и ссылками, которые я не видел никого, о которых упоминалось: ссылки позволяют использовать семантику pass-by-reference в аргументах функции. Указатели, хотя сначала это не видно, нет: они предоставляют только семантику pass-by-value. Это было очень хорошо описано в этой статье .

С уважением, & amp; rzej

12
ответ дан Andrzej 15 August 2018 в 23:13
поделиться
  • 1
    Ссылки и указатели являются как ручками. Они оба дают вам семантику, где ваш объект передается по ссылке, но копируется handle . Нет разницы. (Есть и другие способы иметь ручки, например, ключ для поиска в словаре) – Ben Voigt 7 November 2013 в 19:16
  • 2
    Я тоже так думал. Но см. Связанную статью, описывающую, почему это не так. – Andrzej 12 November 2013 в 11:08
  • 3
    @Andrzj: Это очень длинная версия единственного предложения в моем комментарии: Ручка копируется. – Ben Voigt 12 November 2013 в 17:10
  • 4
    Мне нужно больше объяснений по этому поводу. «Ручка скопирована». Я понимаю некоторые основные идеи, но я думаю, что физически ссылка и указатель указывают на местоположение памяти переменной. Это как alias хранит переменную значения и обновляет ее, поскольку значение переменной изменяется или что-то еще? Я новичок, и, пожалуйста, не называйте это глупым вопросом. – Asim 12 December 2013 в 01:13
  • 5
    – Miles Rout 27 April 2014 в 10:28

Я чувствую, что есть еще один момент, который здесь не был рассмотрен.

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

Хотя это может показаться поверхностным, я считаю, что это свойство имеет решающее значение для ряда функций C ++, например:

  • Шаблоны . Поскольку параметры шаблона заданы в стиле утка, все синтаксические свойства типа имеют значение, поэтому часто один и тот же шаблон можно использовать как с T, так и с T&. (или std::reference_wrapper<T>, который все еще полагается на неявный приведение к T&). Шаблоны, которые охватывают как T&, так и T&&, еще более распространены.
  • Lvalues ​​. Рассмотрим оператор str[0] = 'X'; Без ссылок он будет работать только для c-строк (char* str). Возврат символа по ссылке позволяет пользовательским классам иметь одну и ту же нотацию.
  • Конструкторы копирования . Синтаксически имеет смысл передавать объекты для копирования конструкторов, а не указатели на объекты. Но конструктор копирования просто не может взять объект по значению - это приведет к рекурсивному вызову того же конструктора копий. Это оставляет ссылки как единственный вариант здесь.
  • Перегрузка оператора . С помощью ссылок можно ввести косвенное обращение к вызову оператора - например, operator+(const T& a, const T& b), сохраняя одну и ту же инфиксную нотацию. Это также работает для регулярных перегруженных функций.

Эти точки дают значительную часть C ++ и стандартной библиотеки, поэтому это довольно важное свойство ссылок.

8
ответ дан Ap31 15 August 2018 в 23:13
поделиться

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

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

Целью указателя const можно заменить его адрес и использовать const cast.

Цель ссылки не может быть заменена каким-либо образом, чем UB.

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

98
ответ дан Arkadiy 15 August 2018 в 23:13
поделиться
  • 1
    Я думаю, что это лучший ответ. Другие говорят о ссылках и указателях, как о разных зверях, а затем рассказывают, как они отличаются поведением. Это не облегчает имхо. Я всегда понимал ссылки как T* const с различным синтаксическим сахаром (что случается, чтобы устранить много * и & amp; из вашего кода). – Carlo Wood 10 January 2017 в 02:34
  • 2
    Представьте, что вы пытаетесь сделать cout << 42 << "hello" << endl без ссылок – pm100 11 January 2018 в 20:55
  • 3
    Короткий и лучший ответ – Kad 22 February 2018 в 11:52
  • 4
    «Целевой объект-указатель const может быть заменен принятием его адреса и использованием команды const. Это неопределенное поведение. Подробнее см. В stackoverflow.com/questions/25209838/… . – dgnuff 22 June 2018 в 04:51
  • 5
    Попытка изменить либо референт ссылки, либо значение указателя const (или любого const-скаляра) является незаконным. Что вы можете сделать: удалить квалификацию const, которая была добавлена ​​неявным преобразованием: int i; int const *pci = &i; /* implicit conv to const int* */ int *pi = const_cast<int*>(pci); в порядке. – curiousguy 29 June 2018 в 16:00

Эта программа может помочь в понимании ответа на вопрос. Это простая программа ссылки «j» и указатель «ptr», указывающий на переменную «x».

#include<iostream>

using namespace std;

int main()
{
int *ptr=0, x=9; // pointer and variable declaration
ptr=&x; // pointer to variable "x"
int & j=x; // reference declaration; reference to variable "x"

cout << "x=" << x << endl;

cout << "&x=" << &x << endl;

cout << "j=" << j << endl;

cout << "&j=" << &j << endl;

cout << "*ptr=" << *ptr << endl;

cout << "ptr=" << ptr << endl;

cout << "&ptr=" << &ptr << endl;
    getch();
}

Запустите программу и посмотрите на результат, и вы поймете.

Кроме того, забудьте 10 минут и посмотрите это видео: https://www.youtube.com/watch?v=rlJrrGV0iOg

9
ответ дан Arlene Batada 15 August 2018 в 23:13
поделиться

Ссылка никогда не может быть NULL.

32
ответ дан Cole Johnson 15 August 2018 в 23:13
поделиться
  • 1
    См. Ответ Марка Рэнсома для встречного примера. Это наиболее часто утверждаемый миф о ссылках, но это миф. Единственная гарантия, которую вы имеете по стандарту, заключается в том, что у вас сразу есть UB, когда у вас есть ссылка NULL. Но это похоже на высказывание «Этот автомобиль в безопасности, он никогда не сможет выйти с дороги. (Мы не берем на себя никакой ответственности за то, что может произойти, если вы все равно будете управлять им с дороги. Это может просто взорваться.) & Quot; – cmaster 13 June 2014 в 12:36
  • 2
    @cmaster: В действительной программе ссылка не может быть нулевой. Но указатель может. Это не миф, это факт. – Mehrdad 8 August 2014 в 05:42
  • 3
    @Mehrdad Да, действующие программы остаются на дороге. Но нет барьера для обеспечения того, что ваша программа действительно делает. На больших участках дороги отсутствуют прокладки. Так что очень легко выйти с дороги ночью. И это очень важно для отладки таких ошибок, которые вы знаете : это может случиться: нулевая ссылка может распространяться до того, как она сбой вашей программы, как и нулевой указатель. И когда он делает, у вас есть код вроде void Foo::bar() { virtual_baz(); }, который segfaults. Если вы не знаете, что ссылки могут быть нулевыми, вы не можете отследить нуль до его начала. – cmaster 29 December 2014 в 11:43
  • 4
    int * p = NULL; int & r = * p; ссылка на NULL; if (r) {} - & gt; boOm;) - – sree 4 October 2015 в 12:43
  • 5
    @sree int &r=*p; - неопределенное поведение. В этот момент у вас нет «ссылки, указывающей на NULL», у вас есть программа, о которой больше не может рассуждать о вообще . – cdhowie 28 March 2017 в 18:46

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

#include<iostream>
using namespace std;

void swap(char * &str1, char * &str2)
{
  char *temp = str1;
  str1 = str2;
  str2 = temp;
}

int main()
{
  char *str1 = "Hi";
  char *str2 = "Hello";
  swap(str1, str2);
  cout<<"str1 is "<<str1<<endl;
  cout<<"str2 is "<<str2<<endl;
  return 0;
}

И рассмотрите версию C вышеуказанной программы. В C вы должны использовать указатель на указатель (множественная косвенность), и это приводит к путанице, и программа может выглядеть сложной.

#include<stdio.h>
/* Swaps strings by swapping pointers */
void swap1(char **str1_ptr, char **str2_ptr)
{
  char *temp = *str1_ptr;
  *str1_ptr = *str2_ptr;
  *str2_ptr = temp;
}

int main()
{
  char *str1 = "Hi";
  char *str2 = "Hello";
  swap1(&str1, &str2);
  printf("str1 is %s, str2 is %s", str1, str2);
  return 0;
}

Для получения дополнительной информации о ссылке на указатель посетите следующую страницу:

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

#include <iostream>
using namespace std;

int main()
{
   int x = 10;
   int *ptr = &x;
   int &*ptr1 = ptr;
}
13
ответ дан Destructor 15 August 2018 в 23:13
поделиться

Еще одно интересное использование ссылок состоит в том, чтобы предоставить аргумент по умолчанию для пользовательского типа:

class UDT
{
public:
   UDT() : val_d(33) {};
   UDT(int val) : val_d(val) {};
   virtual ~UDT() {};
private:
   int val_d;
};

class UDT_Derived : public UDT
{
public:
   UDT_Derived() : UDT() {};
   virtual ~UDT_Derived() {};
};

class Behavior
{
public:
   Behavior(
      const UDT &udt = UDT()
   )  {};
};

int main()
{
   Behavior b; // take default

   UDT u(88);
   Behavior c(u);

   UDT_Derived ud;
   Behavior d(ud);

   return 1;
}

По умолчанию используется «привязка const const к временному» аспекту ссылок.

7
ответ дан Don Wakefield 15 August 2018 в 23:13
поделиться

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

void fn1(std::string s);
void fn2(const std::string& s);
void fn3(std::string& s);
void fn4(std::string* s);

void bar() {
    std::string x;
    fn1(x);  // Cannot modify x
    fn2(x);  // Cannot modify x (without const_cast)
    fn3(x);  // CAN modify x!
    fn4(&x); // Can modify x (but is obvious about it)
}

Назад на C, вызов, который выглядит как fn(x), может передаваться только по значению, поэтому он определенно не может изменить x; для изменения аргумента вам нужно будет передать указатель fn(&x). Поэтому, если аргументу не предшествовал &, вы знали, что он не будет изменен. (Обратное, & означает изменение, было неверным, потому что иногда вам приходилось передавать большие структуры только для чтения указателем const.)

Некоторые утверждают, что это такая полезная функция при чтении кода, то параметры указателя всегда должны использоваться для изменяемых параметров, а не для ссылок const, даже если функция никогда не ожидает nullptr. То есть, эти люди утверждают, что сигнатуры функций, такие как fn3() выше, не должны допускаться. Руководства по стилю C ++ для Google являются примером этого.

2
ответ дан Donald Duck 15 August 2018 в 23:13
поделиться

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

    void fun(int &a, int &b); // A common usage of references.
    int a = 0;
    int &b = a; // b is an alias for a. Not so common to use. 
20
ответ дан fatma.ekici 15 August 2018 в 23:13
поделиться

Возможно, некоторые метафоры помогут; В контексте экрана вашего рабочего стола -

  • Ссылка требует, чтобы вы указали фактическое окно.
  • Указателю требуется расположение места на экране, которое вы заверяете он будет содержать ноль или более экземпляров этого типа окна.
7
ответ дан George R 15 August 2018 в 23:13
поделиться

Я всегда решаю это правило из C ++ Core Guidelines:

Предпочитает T * over T & amp; когда «no argument» является допустимым вариантом

1
ответ дан Hitokage 15 August 2018 в 23:13
поделиться
  • 1
    Использование перегруженных функций, которые не принимают указатели вместо того, чтобы разрешать nullptr или использовать терминальные объекты, можно считать гораздо лучшим решением, а не разрешать nullptr в качестве аргументов. – Clearer 19 December 2017 в 10:01
  • 2
    @Clearer Это, вероятно, более чистый, но иногда вам просто нужно быстро передать указатели, и могут быть случаи, когда вам все равно, является ли указатель нулевым или нет. – Hitokage 19 December 2017 в 11:02

Другое отличие состоит в том, что у вас могут быть указатели на тип void (и это означает, что указатель на что-либо), но ссылки на void запрещены.

int a;
void * p = &a; // ok
void & p = a;  //  forbidden

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

9
ответ дан kriss 15 August 2018 в 23:13
поделиться

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

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

Кроме того, есть, конечно, некоторые практические различия между указателями и ссылками. Синтаксис для их использования, очевидно, различен, и вы не можете «пересаживать» ссылки, ссылаться на небытие или ссылаться на ссылки.

24
ответ дан Lightness Races in Orbit 15 August 2018 в 23:13
поделиться

Вопреки распространенному мнению, возможно иметь ссылку, которая является NULL.

int * p = NULL;
int & r = *p;
r = 1;  // crash! (if you're lucky)

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

Технически это недопустимая ссылка, а не нулевая ссылка. C ++ не поддерживает нулевые ссылки как концепцию, как вы можете найти на других языках. Существуют и другие недопустимые ссылки. Любая недопустимая ссылка вызывает призрак неопределенного поведения, так же как и использование недопустимого указателя.

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

Мой пример выше короткий и надуманный. Вот еще пример реального мира.

class MyClass
{
    ...
    virtual void DoSomething(int,int,int,int,int);
};

void Foo(const MyClass & bar)
{
    ...
    bar.DoSomething(i1,i2,i3,i4,i5);  // crash occurs here due to memory access violation - obvious why?
}

MyClass * GetInstance()
{
    if (somecondition)
        return NULL;
    ...
}

MyClass * p = GetInstance();
Foo(*p);

Я хочу повторить, что единственный способ получить нулевую ссылку - это неправильный код, и как только вы его получите, вы получаете неопределенное поведение. Никогда не имеет смысла проверять нулевую ссылку; например, вы можете попробовать if(&bar==NULL)..., но компилятор может оптимизировать утверждение из существования! Действительная ссылка никогда не может быть NULL, поэтому из представления компилятора сравнение всегда неверно, и можно исключить предложение if как мертвый код - это сущность неопределенного поведения.

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

template<typename T>
T& deref(T* p)
{
    if (p == NULL)
        throw std::invalid_argument(std::string("NULL reference"));
    return *p;
}

MyClass * p = GetInstance();
Foo(deref(p));

Для более старого взгляда на эту проблему у кого-то с лучшими навыками письма см. Null References от Jim Hyslop и Herb Sutter.

Еще один пример опасности разыменования нулевого указателя см. в Предоставление неопределенного поведения при попытке передать код на другую платформу Раймондом Ченом.

104
ответ дан Mark Ransom 15 August 2018 в 23:13
поделиться
  • 1
    Этот код содержит неопределенное поведение. Технически вы ничего не можете сделать с нулевым указателем, кроме как установить его, и сравнить его. Когда ваша программа вызывает неопределенное поведение, она может делать что угодно, в том числе работать правильно, пока вы не дадите демо большому боссу. – KeithB 12 September 2008 в 17:00
  • 2
    Знак имеет действительный аргумент. аргумент, что указатель может быть NULL, и вы должны проверить это тоже не реально: если вы говорите, что функция требует не-NULL, то вызывающий должен это сделать. поэтому, если вызывающий абонент не вызывает неопределенное поведение. точно так же, как марка с плохой ссылкой – Johannes Schaub - litb 27 February 2009 в 22:14
  • 3
    Описание ошибочно. Этот код может создать или не создать ссылку NULL. Его поведение не определено. Это может создать совершенно правильную ссылку. Это может вообще не создать какую-либо ссылку. – David Schwartz 20 August 2011 в 12:41
  • 4
    @ Дэвид Шварц, если бы я говорил о том, как все должно было работать в соответствии со стандартом, вы были бы правы. Но это not , о чем я говорю - я говорю о фактическом наблюдаемом поведении с очень популярным компилятором и экстраполирую на основе моих знаний о типичных компиляторах и архитектурах процессора, что будет вероятно . Если вы считаете, что ссылки превосходят указатели, потому что они более безопасны и не считают, что ссылки могут быть плохими, вы столкнулись с простой проблемой когда-нибудь так же, как и я. – Mark Ransom 22 August 2011 в 03:11
  • 5
    Разыменование нулевого указателя неверно. Любая программа, которая делает это, даже для инициализации ссылки, неверна. Если вы инициализируете ссылку из указателя, вы всегда должны проверить, что указатель действителен. Даже если это удается, базовый объект может быть удален в любое время, оставляя ссылку ссылкой на несуществующий объект, правильно? То, что вы говорите, это хороший материал. Я думаю, что реальная проблема здесь заключается в том, что ссылку НЕ нужно проверять на «нулевость». когда вы видите один, и указатель должен быть, как минимум, утверждён. – t0rakka 22 March 2017 в 15:07

Разница между указателем и ссылкой

Указатель может быть инициализирован равным 0, а ссылка не указана. Фактически ссылка должна также ссылаться на объект, но указатель может быть нулевым указателем:

int* p = 0;

Но мы не можем иметь int& p = 0;, а также int& p=5 ;.

На самом деле, чтобы сделать это правильно, мы должны были объявить и определить объект в первом, тогда мы сможем сделать ссылку на этот объект, поэтому правильная реализация предыдущего кода будет:

Int x = 0;
Int y = 5;
Int& p = x;
Int& p1 = y;

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

Другое отличие заключается в том, что указатель может указывать на другой объект, однако ссылка всегда ссылается на тот же объект, возьмем этот пример:

Int a = 6, b = 5;
Int& rf = a;

Cout << rf << endl; // The result we will get is 6, because rf is referencing to the value of a.

rf = b;
cout << a << endl; // The result will be 5 because the value of b now will be stored into the address of a so the former value of a will be erased

Еще один момент: когда у нас есть шаблон, подобный шаблону STL, такой тип шаблона всегда будет возвращать ссылку, а не указатель, чтобы упростить чтение или присвоение нового значения с помощью оператора []:

Std ::vector<int>v(10); // Initialize a vector with 10 elements
V[5] = 5; // Writing the value 5 into the 6 element of our vector, so if the returned type of operator [] was a pointer and not a reference we should write this *v[5]=5, by making a reference we overwrite the element by using the assignment "="
301
ответ дан Peter Mortensen 15 August 2018 в 23:13
поделиться
  • 1
    @Orion Edwards & gt; член-доступ с использованием указателей - & gt; & член-доступ с использованием ссылок. Это не соответствует действительности на 100%. У вас может быть ссылка на указатель. В этом случае вы получите доступ к элементам указателя с привязкой, используя - & gt; struct Node {Node * next; }; Узел * сначала; // p - ссылка на указатель void foo (Node * & amp; p) {p- & gt; next = first; } Узел * bar = новый узел; Foo (бар); - OP: Вы знакомы с понятиями rvalues ​​и lvalues? – user 12 September 2008 в 13:57
  • 2
    Ссылка - это ссылка на l-значение, не обязательно на переменную. Из-за этого он намного ближе к указателю, чем к реальному псевдониму (конструкция времени компиляции). Примерами выражений, на которые можно ссылаться, являются * p или даже * p ++ – Arkadiy 2 March 2009 в 17:27
  • 3
    Правильно, я просто указывал на то, что ссылка может не всегда подталкивать новую переменную в стек так, как будет выглядеть новый указатель. – Vincent Robert 3 March 2009 в 21:36
  • 4
    но для чего это используется? – Ahmad Mushtaq 22 October 2009 в 15:10
  • 5
    Ну, s3_copy создаст временную, а затем скопирует ее в s3_copy, тогда как s3_reference напрямую использует временную. Затем, чтобы быть действительно педантичным, вам нужно взглянуть на Оптимизацию возвращаемого значения, в соответствии с которой компилятору разрешено исключить построение копии в первом случае. – Matt Price 22 October 2009 в 19:14
  • 6
    @digitalSurgeon: Магия там довольно сильная. Время жизни объекта расширяется фактом связывания const & и только тогда, когда ссылка выходит за пределы области действия деструктора ссылочного типа actual (по сравнению с ссылочным типом, который может быть база). Поскольку это ссылка, между ними не будет нарезки. – David Rodríguez - dribeas 14 January 2010 в 18:06
  • 7
    @kriss: Нет, вы также можете получить обвисшую ссылку, возвращая автоматическую переменную по ссылке. – Ben Voigt 2 November 2010 в 07:14
  • 8
    @kriss: для компилятора практически невозможно обнаружить в общем случае. Рассмотрим функцию-член, которая возвращает ссылку на переменную-член класса: это безопасно и не должно быть запрещено компилятором. Затем вызывающий, который имеет автоматический экземпляр этого класса, вызывает эту функцию-член и возвращает ссылку. Престо: оборванная ссылка. И да, это вызовет проблемы, @kriss: это моя точка зрения. Многие утверждают, что преимущество ссылок на указатели состоит в том, что ссылки всегда действительны, но это не так. – Ben Voigt 2 November 2010 в 14:15
  • 9
    @kriss: Нет, ссылка на объект с автоматической продолжительностью хранения сильно отличается от временного объекта. Во всяком случае, я просто предоставлял вам контрпример вашего утверждения, что вы можете получить недопустимую ссылку, разыменовывая неверный указатель. Кристоф прав - ссылки не являются более безопасными, чем указатели, программа, которая использует ссылки, может по-прежнему нарушать безопасность типов. – Ben Voigt 2 November 2010 в 16:15
  • 10
    Ссылки не являются своего рода указателем. Это новое имя для существующего объекта. – catphive 20 July 2011 в 02:28
  • 11
    @catphive: true, если вы идете по семантике языка, а не true, если вы действительно смотрите на реализацию; C ++ - гораздо более «магический» язык, который C, и если вы удалите магию из ссылок, вы получите указатель – Christoph 23 July 2011 в 10:07
  • 12
    @VincentRobert: он будет действовать так же, как указатель ... если функция встроена, как ссылка, так и указатель будут оптимизированы. Если есть вызов функции, адрес объекта должен быть передан функции. – Ben Voigt 14 February 2012 в 01:08
  • 13
    Правда, тело должно быть видимым. Однако определение того, что maybeModify не принимает адрес чего-либо, связанного с x, существенно проще, чем доказательство того, что связка арифметики указателя не встречается. – Cort Ammon 11 September 2013 в 05:27
  • 14
    Я считаю, что оптимизатор уже делает, что «пучок арифметики указателя не возникает» проверьте наличие других причин. – Ben Voigt 11 September 2013 в 05:32
  • 15
    Обновление для C ++ 11: последнее предложение должно быть прочитано & quot; Вы не можете привязывать ссылку на константу без ссылки на временную & quot; потому что вы можете привязать ссылку non-const rvalue к временному, и она имеет такое же поведение продления жизни. – Oktalist 10 November 2013 в 22:14
  • 16
    У смарт-указателей есть и то, и другое. (методы класса интеллектуального указателя) и - & gt; (методы для базового типа). – JBRWilkinson 9 April 2014 в 10:11
  • 17
    @ user6105 Операция Orion Edwards фактически на 100% истинна. "члены доступа [указателя de-referenced указателя & quot; Указатель не имеет каких-либо членов. Объект, на который ссылается указатель, имеет членов, и доступ к ним - это то, что -> предоставляет ссылки на указатели, так же как и с самим указателем. – Max Truxa 15 April 2015 в 17:37
  • 18
    И если класс имеет ссылочную переменную, он должен быть инициализирован с помощью nullptr или действительного объекта в списке инициализации. – Misgevolution 15 June 2015 в 17:32
  • 19
    int * p = NULL; int & r = * p; ссылка на NULL; if (r) {} - & gt; boOm;) – sree 4 October 2015 в 12:37
  • 20
    Формулировка в этом ответе слишком сбивает с толку, поскольку он очень полезен. Кроме того, @Misgevolution, вы серьезно рекомендуете читателям инициализировать ссылку с помощью nullptr? Вы действительно читали какую-либо другую часть этой темы или ...? – underscore_d 11 October 2015 в 17:27
  • 21
    & quot; Ссылки очень похожи на указатели & quot; - семантически, в соответствующих контекстах - но с точки зрения сгенерированного кода - только в некоторых реализациях, а не через какое-либо определение / требование. Я знаю, что вы указали это, и я не согласен с каким-либо вашим сообщением в практическом плане, но у нас слишком много проблем, когда люди слишком много читают в сокращенных описаниях, таких как «ссылки похожи на / обычно реализуются как указатели», , – underscore_d 11 October 2015 в 17:31
  • 22
    Этот фокус на этапе компиляции кажется приятным, пока вы не вспомните, что ссылки могут быть переданы во время выполнения, после чего статическое сглаживание выходит из окна. (И тогда ссылки обычно реализованы как указатели, но стандарт не требует этого метода.) – underscore_d 11 October 2015 в 17:35
  • 23
    Мой плохой, извините за ту глупую вещь, которую я сказал. Я, должно быть, был лишен сна к тому времени. 'initialize with nullptr' абсолютно неверен. – Misgevolution 11 October 2015 в 18:09
  • 24
    У меня такое чувство, что кто-то ошибочно помечен как устаревший комментарий в соответствии с void maybeModify(int& x) { 1[&x]++; }, о котором говорится в других комментариях выше – Ben Voigt 4 December 2015 в 00:28
  • 25
    почему . и -> имеют какое-то отношение к vi и emacs :) – artm 21 August 2016 в 00:45
  • 26
    @artM - это была шутка, и, вероятно, это не имеет смысла для не-родных английских ораторов. Мои извинения. Чтобы объяснить, является ли vi лучше, чем emacs, является полностью субъективным. Некоторые люди думают, что vi намного превосходит, а другие считают совершенно противоположным. Точно так же я думаю, что использование . лучше, чем использование ->, но так же, как vi vs emacs, это полностью субъективно, и вы ничего не можете доказать – Orion Edwards 25 August 2016 в 21:41
  • 27
    Мы все еще можем иметь const int& i = 0. – Revolver_Ocelot 6 January 2017 в 15:24
  • 28
    В этом случае ссылка будет использоваться только в чтении, мы не можем модифицировать эту константную ссылку даже при использовании «const_cast». потому что "const_cast" принимайте только указатель, а не ссылку. – dhokar.w 6 January 2017 в 15:37
  • 29
    const_cast работает со ссылками довольно хорошо: coliru.stacked-crooked.com/a/eebb454ab2cfd570 – Revolver_Ocelot 6 January 2017 в 17:52
  • 30
    вы делаете актерский состав, чтобы не ссылаться на эту ссылку, попробуйте это; const int & amp; я =; const_cast & л; INT & GT; (я); я пытаюсь выбросить константу ссылки, чтобы сделать возможной запись и присвоение нового значения ссылке, но это невозможно. пожалуйста, сосредоточиться !! – dhokar.w 6 January 2017 в 20:38
  • 31
    Вы можете написать &r + offset, где r был объявлен как ссылка – M.M 23 February 2017 в 06:13
  • 32
    @AhmadMushtaq: ключевым использованием этого является производные классы . Если нет наследования, вы можете использовать семантику значений, которая будет дешевой или бесплатной из-за конструкции RVO / move. Но если у вас есть Animal x = fast ? getHare() : getTortoise(), тогда x столкнутся с проблемой классической резки, а Animal& x = ... будет работать правильно. – Arthur Tacca 2 November 2017 в 12:04

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

int& j = i;

Он внутренне становится

int* const j = &i;
14
ответ дан Ryan 15 August 2018 в 23:13
поделиться
  • 1
    Это не то, что говорит C ++ Standard, и компилятору не требуется выполнять ссылки так, как описано в вашем ответе. – jogojapan 26 February 2013 в 07:22
  • 2
    @jogojapan: Любой способ, который подходит для компилятора C ++ для реализации ссылки, также является допустимым способом реализации указателя const. Эта гибкость не доказывает, что существует разница между ссылкой и указателем. – Ben Voigt 26 August 2015 в 23:00
  • 3
    @BenVoigt Может быть, что любая действительная реализация одного из них также является допустимой реализацией другой, но это не следует очевидным образом из определений этих двух понятий. Хороший ответ начался бы с определений и показал, почему утверждение о том, что они в конечном счете совпадают, верно. Этот ответ, похоже, является своего рода комментарием к некоторым другим ответам. – jogojapan 26 August 2015 в 23:41
  • 4
    Ссылка - другое имя, присвоенное объекту. Компилятору разрешено иметь какую-либо реализацию, если вы не можете отличить эту информацию, это называется «как-будто», править. Важная часть здесь заключается в том, что вы не можете сказать разницу. Если вы обнаружите, что указатель не имеет хранилища, компилятор ошибочен. Если вы обнаружите, что ссылка не имеет хранилища, компилятор по-прежнему соответствует. – sp2danny 6 September 2017 в 14:52

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

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

Например:

class scope_test
{
public:
    ~scope_test() { printf("scope_test done!\n"); }
};

...

{
    const scope_test &test= scope_test();
    printf("in scope\n");
}

будет печатать:

in scope
scope_test done!

Это языковой механизм, который позволяет ScopeGuard работать.

14
ответ дан Tim Cooper 15 August 2018 в 23:13
поделиться
  • 1
    Вы не можете взять адрес ссылки, но это не значит, что они физически не занимают место. Устраняя оптимизацию, они, безусловно, могут. – Lightness Races in Orbit 24 April 2011 в 17:27
  • 2
    Несмотря на это влияние, «Ссылка на стек не занимает вообще никакого места», явно ложно. – Lightness Races in Orbit 26 April 2011 в 00:09
  • 3
    @Tomalak, ну, это зависит и от компилятора. Но да, сказав, что это немного запутанно. Полагаю, было бы не так просто сбить это. – MSN 26 April 2011 в 22:52
  • 4
    В любом конкретном случае он может или не может. Так что «это не так» поскольку категорическое утверждение неверно. Вот что я говорю. :) [Я не помню, что говорит стандарт по этому вопросу; правила ссылочных членов могут распространять общее правило «ссылки могут занимать место», но у меня нет моей копии стандарта со мной здесь, на пляже: D] – Lightness Races in Orbit 26 April 2011 в 23:22

Рискуя добавить в замешательство, я хочу добавить какой-то ввод, я уверен, что это в основном зависит от того, как компилятор реализует ссылки, но в случае gcc идея о том, что ссылка может указывать только на переменную на стеке на самом деле не правильно, возьмите это, например:

#include <iostream>
int main(int argc, char** argv) {
    // Create a string on the heap
    std::string *str_ptr = new std::string("THIS IS A STRING");
    // Dereference the string on the heap, and assign it to the reference
    std::string &str_ref = *str_ptr;
    // Not even a compiler warning! At least with gcc
    // Now lets try to print it's value!
    std::cout << str_ref << std::endl;
    // It works! Now lets print and compare actual memory addresses
    std::cout << str_ptr << " : " << &str_ref << std::endl;
    // Exactly the same, now remember to free the memory on the heap
    delete str_ptr;
}

Что выводит это:

THIS IS A STRING
0xbb2070 : 0xbb2070

Если вы заметили, что адреса памяти точно совпадают, ссылка успешно указывает на переменную в куче! Теперь, если вы действительно хотите получить freaky, это также работает:

int main(int argc, char** argv) {
    // In the actual new declaration let immediately de-reference and assign it to the reference
    std::string &str_ref = *(new std::string("THIS IS A STRING"));
    // Once again, it works! (at least in gcc)
    std::cout << str_ref;
    // Once again it prints fine, however we have no pointer to the heap allocation, right? So how do we free the space we just ignorantly created?
    delete &str_ref;
    /*And, it works, because we are taking the memory address that the reference is
    storing, and deleting it, which is all a pointer is doing, just we have to specify
    the address with '&' whereas a pointer does that implicitly, this is sort of like
    calling delete &(*str_ptr); (which also compiles and runs fine).*/
}

Что выводит это:

THIS IS A STRING

Поэтому ссылка является указателем под капотом, они оба являются просто сохранение адреса памяти, в котором указывает адрес, не имеет значения, что, по вашему мнению, произойдет, если я вызову std :: cout & lt; & lt; str_ref; ПОСЛЕ вызова delete & amp; str_ref? Ну, очевидно, что он компилируется нормально, но вызывает ошибку сегментации во время выполнения, потому что он больше не указывает на допустимую переменную, мы по существу имеем сломанную ссылку, которая все еще существует (пока она не выпадает из области), но бесполезна.

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

Теперь, независимо от того, как компилятор обрабатывает ссылки, он всегда будет иметь какой-то указатель под капотом, потому что ссылка должна ссылаться на конкретную переменную в определенном адресе памяти, чтобы она работала так, как ожидалось, не обойти это (отсюда и термин «ссылка»).

Единственное важное правило, которое важно запомнить с помощью ссылок, заключается в том, что они должны определяется во время объявления (за исключением ссылки в заголовке, в этом случае это должно быть определено ined in the constructor, после того, как объект, в который он содержится, построен слишком поздно, чтобы определить его).

Помните, что мои примеры выше - это просто примеры, демонстрирующие, что такое ссылка, вы никогда не захотите использовать ссылка в этом смысле! Для правильного использования ссылки здесь уже много ответов, которые поражают гвоздь на голове

11
ответ дан Tory 15 August 2018 в 23:13
поделиться

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

Ссылки менее эффективны, чем указатели

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

2) Ссылки не могут быть NULL. Указатели часто делают NULL, чтобы указать, что они не указывают на какую-либо действительную вещь.

3) Ссылка должна быть инициализирована при объявлении. Нет такого ограничения с указателями

Из-за вышеуказанных ограничений ссылки в C ++ не могут использоваться для реализации структур данных, таких как Linked List, Tree и т. Д. В Java ссылки не указаны выше ограничений и может использоваться для реализации всех структур данных. Ссылки, более мощные в Java, являются основной причиной, по которой Java не нуждается в указателях.

Ссылки более безопасны и удобны в использовании:

1) Безопаснее: поскольку ссылки должны быть инициализированы, дикие ссылки, такие как дикие указатели, вряд ли будут существовать. Все еще возможно иметь ссылки, которые не относятся к допустимому местоположению

2) Легче использовать: для доступа к значению не требуется оператор разыменования. Они могут использоваться как обычные переменные. Оператор '& amp;' необходим только во время объявления. Кроме того, к элементам ссылки объекта можно обращаться с помощью оператора точек ('.'), В отличие от указателей, где для доступа к элементам необходим оператор стрелки (->).

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

10
ответ дан Yogeesh H T 15 August 2018 в 23:13
поделиться

Разница заключается в том, что переменная указателя константы (не путать с указателем на константу) может быть изменена в какое-то время во время выполнения программы, требуется использовать семантику указателя (& amp;, *), а ссылки могут устанавливаются только при инициализации (поэтому вы можете устанавливать их только в списке инициализаторов конструктора, но не как-то иначе) и использовать обычную доступность для семантики. В основном были введены ссылки, позволяющие поддерживать перегрузку операторов, как я читал в какой-то очень старой книге. Как кто-то сказал в этом потоке - указатель может быть установлен в 0 или любое другое значение, которое вы хотите. 0 (NULL, nullptr) означает, что указатель инициализирован ничем. Это ошибка для разыменования нулевого указателя. Но на самом деле указатель может содержать значение, которое не указывает на правильное расположение памяти. В свою очередь, ссылки не позволяют пользователю инициализировать ссылку на то, на что нельзя ссылаться, из-за того, что вы всегда предоставляете ему значение правильного типа. Хотя есть много способов сделать ссылочную переменную инициализированной неправильной ячейкой памяти - вам лучше не углубляться в детали. На уровне машины оба указателя и ссылки работают равномерно - с помощью указателей. Скажем, в основных ссылках речь идет о синтаксическом сахаре. Ссылки rvalue отличаются от этого - они, естественно, представляют собой объекты stack / heap.

4
ответ дан Zorgiev 15 August 2018 в 23:13
поделиться

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

Рассмотрим эти два фрагмента программы. В первом мы назначаем один указатель на другой:

int ival = 1024, ival2 = 2048;
int *pi = &ival, *pi2 = &ival2;
pi = pi2;    // pi now points to ival2

После назначения ival объект, адресуемый pi, остается неизменным. Назначение изменяет значение pi, указывая на другой объект. Теперь рассмотрим аналогичную программу, которая присваивает две ссылки:

int &ri = ival, &ri2 = ival2;
ri = ri2;    // assigns ival2 to ival

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

30
ответ дан Андрей Беньковский 15 August 2018 в 23:13
поделиться
  • 1
    «ссылка всегда относится к объекту». просто полностью ложно – Ben Voigt 21 July 2017 в 18:29

Я использую ссылки, если мне не требуется ни одно из них:

  • Нулевые указатели могут использоваться как контрольное значение, часто это дешевый способ избежать перегрузки функций или использования bool.
  • Вы можете сделать арифметику на указателе. Например, p += offset;
301
ответ дан Peter Mortensen 15 August 2018 в 23:13
поделиться
  • 1
    @Orion Edwards & gt; член-доступ с использованием указателей - & gt; & член-доступ с использованием ссылок. Это не соответствует действительности на 100%. У вас может быть ссылка на указатель. В этом случае вы получите доступ к элементам указателя с привязкой, используя - & gt; struct Node {Node * next; }; Узел * сначала; // p - ссылка на указатель void foo (Node * & amp; p) {p- & gt; next = first; } Узел * bar = новый узел; Foo (бар); - OP: Вы знакомы с понятиями rvalues ​​и lvalues? – user 12 September 2008 в 13:57
  • 2
    Ссылка - это ссылка на l-значение, не обязательно на переменную. Из-за этого он намного ближе к указателю, чем к реальному псевдониму (конструкция времени компиляции). Примерами выражений, на которые можно ссылаться, являются * p или даже * p ++ – Arkadiy 2 March 2009 в 17:27
  • 3
    Правильно, я просто указывал на то, что ссылка может не всегда подталкивать новую переменную в стек так, как будет выглядеть новый указатель. – Vincent Robert 3 March 2009 в 21:36
  • 4
    но для чего это используется? – Ahmad Mushtaq 22 October 2009 в 15:10
  • 5
    Ну, s3_copy создаст временную, а затем скопирует ее в s3_copy, тогда как s3_reference напрямую использует временную. Затем, чтобы быть действительно педантичным, вам нужно взглянуть на Оптимизацию возвращаемого значения, в соответствии с которой компилятору разрешено исключить построение копии в первом случае. – Matt Price 22 October 2009 в 19:14
  • 6
    @digitalSurgeon: Магия там довольно сильная. Время жизни объекта расширяется фактом связывания const & и только тогда, когда ссылка выходит за пределы области действия деструктора ссылочного типа actual (по сравнению с ссылочным типом, который может быть база). Поскольку это ссылка, между ними не будет нарезки. – David Rodríguez - dribeas 14 January 2010 в 18:06
  • 7
    @kriss: Нет, вы также можете получить обвисшую ссылку, возвращая автоматическую переменную по ссылке. – Ben Voigt 2 November 2010 в 07:14
  • 8
    @kriss: для компилятора практически невозможно обнаружить в общем случае. Рассмотрим функцию-член, которая возвращает ссылку на переменную-член класса: это безопасно и не должно быть запрещено компилятором. Затем вызывающий, который имеет автоматический экземпляр этого класса, вызывает эту функцию-член и возвращает ссылку. Престо: оборванная ссылка. И да, это вызовет проблемы, @kriss: это моя точка зрения. Многие утверждают, что преимущество ссылок на указатели состоит в том, что ссылки всегда действительны, но это не так. – Ben Voigt 2 November 2010 в 14:15
  • 9
    @kriss: Нет, ссылка на объект с автоматической продолжительностью хранения сильно отличается от временного объекта. Во всяком случае, я просто предоставлял вам контрпример вашего утверждения, что вы можете получить недопустимую ссылку, разыменовывая неверный указатель. Кристоф прав - ссылки не являются более безопасными, чем указатели, программа, которая использует ссылки, может по-прежнему нарушать безопасность типов. – Ben Voigt 2 November 2010 в 16:15
  • 10
    Ссылки не являются своего рода указателем. Это новое имя для существующего объекта. – catphive 20 July 2011 в 02:28
  • 11
    @catphive: true, если вы идете по семантике языка, а не true, если вы действительно смотрите на реализацию; C ++ - гораздо более «магический» язык, который C, и если вы удалите магию из ссылок, вы получите указатель – Christoph 23 July 2011 в 10:07
  • 12
    @VincentRobert: он будет действовать так же, как указатель ... если функция встроена, как ссылка, так и указатель будут оптимизированы. Если есть вызов функции, адрес объекта должен быть передан функции. – Ben Voigt 14 February 2012 в 01:08
  • 13
    Правда, тело должно быть видимым. Однако определение того, что maybeModify не принимает адрес чего-либо, связанного с x, существенно проще, чем доказательство того, что связка арифметики указателя не встречается. – Cort Ammon 11 September 2013 в 05:27
  • 14
    Я считаю, что оптимизатор уже делает, что «пучок арифметики указателя не возникает» проверьте наличие других причин. – Ben Voigt 11 September 2013 в 05:32
  • 15
    Обновление для C ++ 11: последнее предложение должно быть прочитано & quot; Вы не можете привязывать ссылку на константу без ссылки на временную & quot; потому что вы можете привязать ссылку non-const rvalue к временному, и она имеет такое же поведение продления жизни. – Oktalist 10 November 2013 в 22:14
  • 16
    У смарт-указателей есть и то, и другое. (методы класса интеллектуального указателя) и - & gt; (методы для базового типа). – JBRWilkinson 9 April 2014 в 10:11
  • 17
    @ user6105 Операция Orion Edwards фактически на 100% истинна. "члены доступа [указателя de-referenced указателя & quot; Указатель не имеет каких-либо членов. Объект, на который ссылается указатель, имеет членов, и доступ к ним - именно то, что -> предоставляет ссылки на указатели, так же как и с самим указателем. – Max Truxa 15 April 2015 в 17:37
  • 18
    И если класс имеет ссылочную переменную, он должен быть инициализирован с помощью nullptr или действительного объекта в списке инициализации. – Misgevolution 15 June 2015 в 17:32
  • 19
    int * p = NULL; int & r = * p; ссылка на NULL; if (r) {} - & gt; boOm;) – sree 4 October 2015 в 12:37
  • 20
    Формулировка в этом ответе слишком сбивает с толку, поскольку он очень полезен. Кроме того, @Misgevolution, вы серьезно рекомендуете читателям инициализировать ссылку с помощью nullptr? Вы действительно читали какую-либо другую часть этой темы или ...? – underscore_d 11 October 2015 в 17:27
  • 21
    & quot; Ссылки очень похожи на указатели & quot; - семантически, в соответствующих контекстах - но с точки зрения сгенерированного кода - только в некоторых реализациях, а не через какое-либо определение / требование. Я знаю, что вы указали это, и я не согласен с каким-либо вашим сообщением в практическом плане, но у нас слишком много проблем, когда люди слишком много читают в сокращенных описаниях, таких как «ссылки похожи на / обычно реализуются как указатели», , – underscore_d 11 October 2015 в 17:31
  • 22
    Этот фокус на этапе компиляции кажется приятным, пока вы не вспомните, что ссылки могут быть переданы во время выполнения, после чего статическое сглаживание выходит из окна. (И тогда ссылки обычно реализованы как указатели, но стандарт не требует этого метода.) – underscore_d 11 October 2015 в 17:35
  • 23
    Мой плохой, извините за ту глупую вещь, которую я сказал. Я, должно быть, был лишен сна к тому времени. 'initialize with nullptr' абсолютно неверен. – Misgevolution 11 October 2015 в 18:09
  • 24
    У меня такое чувство, что кто-то ошибочно помечен как устаревший комментарий в соответствии с void maybeModify(int& x) { 1[&x]++; }, о котором говорится в других комментариях выше – Ben Voigt 4 December 2015 в 00:28
  • 25
    почему . и -> имеют какое-то отношение к vi и emacs :) – artm 21 August 2016 в 00:45
  • 26
    @artM - это была шутка, и, вероятно, это не имеет смысла для не-родных английских ораторов. Мои извинения. Чтобы объяснить, является ли vi лучше, чем emacs, является полностью субъективным. Некоторые люди думают, что vi намного превосходит, а другие считают совершенно противоположным. Точно так же я думаю, что использование . лучше, чем использование ->, но так же, как vi vs emacs, это полностью субъективно, и вы ничего не можете доказать – Orion Edwards 25 August 2016 в 21:41
  • 27
    Вы можете написать &r + offset, где r был объявлен как ссылка – M.M 23 February 2017 в 06:13
  • 28
    @AhmadMushtaq: ключевым использованием этого является производные классы . Если нет наследования, вы можете использовать семантику значений, которая будет дешевой или бесплатной из-за конструкции RVO / move. Но если у вас есть Animal x = fast ? getHare() : getTortoise(), тогда x столкнутся с проблемой классической резки, а Animal& x = ... будет работать правильно. – Arthur Tacca 2 November 2017 в 12:04
Другие вопросы по тегам:

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