Автор Тема: C++ инициализация ссылок  (Прочитано 56301 раз)

Berserker

  • Sr. Member
  • ****
  • Сообщений: 254
    • Просмотр профиля
C++ инициализация ссылок
« : Март 14, 2013, 04:55:01 pm »
Подскажите, пожалуйста, если есть знатоки.
Обыскал весь инет, везде твердится одно и то же: ссылки инициализируются единожды. Повторная установка невозможна.

Как тогда GNU C++ компилирует это:

for (size_t i = 0; i < scheta_.size(); i++)
{
  const Schyot &schyot = scheta_; // На каждой итерации разный объект
  ..
}

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: C++ инициализация ссылок
« Ответ #1 : Март 14, 2013, 05:18:30 pm »
Подскажите, пожалуйста, если есть знатоки.
Обыскал весь инет, везде твердится одно и то же: ссылки инициализируются единожды. Повторная установка невозможна.

Как тогда GNU C++ компилирует это:

for (size_t i = 0; i < scheta_.size(); i++)
{
  const Schyot &schyot = scheta_; // На каждой итерации разный объект
  ..
}
А какие проблемы? Время жизни переменной - блок. При каждой итерации "блок" создается заново. То есть все переменные что объявлены в блоке создаются заново (понятно что там могут быть оптимизации, но семантически это так).

То же самое что и в случае функции:
void foo(int i) {
    const Bar b& = some_bar[i];
    std::cout << b << std::endl;
}

void boo() {
    for (size_t i=0; i<100500; i++) foo(i);
}

Разницы никакой (более того, и код будет сгенерирован наверняка идентичный).

PS. А что такое GNU C++? Вроде бы обычный стандартный C++98 в данном коде.
Y = λf.(λx.f (x x)) (λx.f (x x))

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: C++ инициализация ссылок
« Ответ #2 : Март 14, 2013, 05:22:48 pm »
На всякий случай поясню - объявление переменной по месту использования в С++ это НЕ синтаксический сахар над VAR-блоком Оберона, тут реально другая семантика, и в том же Обероне подобно сэмулировать вменяемым образом невозможно. Соответственно нельзя нормально понять семантику С++ не выйдя за границы семантики Оберона.
Y = λf.(λx.f (x x)) (λx.f (x x))

Berserker

  • Sr. Member
  • ****
  • Сообщений: 254
    • Просмотр профиля
Re: C++ инициализация ссылок
« Ответ #3 : Март 14, 2013, 05:40:44 pm »
Спасибо. Именно то, что я искал. Значит время жизни переменной в теле цикла — одна итерация. Сбил меня ответ по C#:

Цитировать
Most of the time, it does not matter whether you declare a variable inside or outside the loop; the rules of definite assignment ensure that it doesn't matter.

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

GNU C++ Compiler имелся в виду.
« Последнее редактирование: Март 14, 2013, 05:43:17 pm от Berserker »

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: C++ инициализация ссылок
« Ответ #4 : Март 14, 2013, 05:55:27 pm »
Спасибо. Именно то, что я искал. Значит время жизни переменной в теле цикла — одна итерация. Сбил меня ответ по C#:

Цитировать
Most of the time, it does not matter whether you declare a variable inside or outside the loop; the rules of definite assignment ensure that it doesn't matter.
А при чем тут шарп? Это вообще другой язык, к плюсам не имеющий никакого отношения. Там ссылок аналогичных плюсам просто нет.

С тем же успехом можно было читать ответ по Аде или там хаскелю :-)
Y = λf.(λx.f (x x)) (λx.f (x x))

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: C++ инициализация ссылок
« Ответ #5 : Март 15, 2013, 01:09:09 am »
Кстати, а для чего и зачем C++ используешь?
Y = λf.(λx.f (x x)) (λx.f (x x))

Berserker

  • Sr. Member
  • ****
  • Сообщений: 254
    • Просмотр профиля
Re: C++ инициализация ссылок
« Ответ #6 : Март 15, 2013, 04:19:39 pm »
Ссылки — это автоматически разыменовываемые указатели. Практически полный аналог (*obj). И реализуются они в 99.99% (если не 100%) через указатели.
Почему ссылки запретили явно переустанавливать не ясно, в итоге функциональность пострадала, а плюсов не видно.

При желании можно изменить ссылку вполне легально.

Код: (c++) [Выделить]
string s[3];
s[0] = "1";
s[1] = "2";
s[2] = "3";

int i = 0;

reseat_reference: const string &ref = s[i];
kon << ref;
i++;

if (i <= 2)
{
  goto reseat_reference;
}

Результат: 123 в консоли.

Цитировать
Кстати, а для чего и зачем C++ используешь?
Первый раз в образовательных целях. Простейший сервер, выдающий по прямому запросу текущее изображение рабочего стола в jpg-формате. Второй раз были лабораторные студентам.

Сейчас начал переписывать модуль с Делфи на С++, виртуализирующий набор WinAPI для работы с файловой системой. В результате можно подключать любые папки в качестве корневого каталога программы для реализации системы модов. Ещё не дописал.

Сейчас нужно сделать эмулятор работы терминала банка и самого банка для студентов в рамках изучения дисциплины «Проектирование информационных систем» и генерации кода из UML-диаграм в Rational Rose 2003.

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: C++ инициализация ссылок
« Ответ #7 : Март 15, 2013, 04:37:59 pm »
Ссылки — это автоматически разыменовываемые указатели. Практически полный аналог (*obj). И реализуются они в 99.99% (если не 100%) через указатели.
Почему ссылки запретили явно переустанавливать не ясно, в итоге функциональность пострадала, а плюсов не видно.

При желании можно изменить ссылку вполне легально.

Код: (c++) [Выделить]
string s[3];
s[0] = "1";
s[1] = "2";
s[2] = "3";

int i = 0;

reseat_reference: const string &ref = s[i];
kon << ref;
i++;

if (i <= 2)
{
  goto reseat_reference;
}

Результат: 123 в консоли.
1) это не изменение ссылки.
2) ссылка это алиас а не аналог указателя.

Перепиши, пожалуйста, вот этот код на указателях:
struct O {int foo;};

O foo() {
    O o = {42};
    return o;
}

int main() {
    const O& o = foo();
    cout << o.foo;
    return 0;
}
Результат конечно должен быть чистым, то есть чтобы при любых флагах компилятора не было варнингов.

Цитировать
Сейчас начал переписывать модуль с Делфи на С++, виртуализирующий набор WinAPI для работы с файловой системой. В результате можно подключать любые папки в качестве корневого каталога программы для реализации системы модов. Ещё не дописал.

Сейчас нужно сделать эмулятор работы терминала банка и самого банка для студентов в рамках изучения дисциплины «Проектирование информационных систем» и генерации кода из UML-диаграм в Rational Rose 2003.
Прикольно.
Y = λf.(λx.f (x x)) (λx.f (x x))

Berserker

  • Sr. Member
  • ****
  • Сообщений: 254
    • Просмотр профиля
Re: C++ инициализация ссылок
« Ответ #8 : Март 15, 2013, 04:50:47 pm »
Цитировать
1) это не изменение ссылки.
А что тогда? Ссылка (на физической уровне указатель) сперва содержит адрес s[0], потом s[1], потом s[2].

Цитировать
struct O {int foo;};

O foo() {
    O o = {42};
    return o;
}

int main() {
    const O& o = foo();
    cout << o.foo;
    return 0;
}

Я не профессионал, поправьте, если ошибусь.

Код: (c++) [Выделить]
const O o = foo();
cout << o.foo;
return 0;

Фактически в Вашем коде:

Код: (c++) [Выделить]
O temp;
foo(&temp);
const O& o = temp;

У меня:

Код: (c++) [Выделить]
O temp;
foo(&temp);
// Здесь могло бы быть бессмысленное копирование временной структуры в такую же временную
const O& o = temp;

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re: C++ инициализация ссылок
« Ответ #9 : Март 15, 2013, 05:40:27 pm »
Ссылки — это автоматически разыменовываемые указатели. Практически полный аналог (*obj). И реализуются они в 99.99% (если не 100%) через указатели.
Почему ссылки запретили явно переустанавливать не ясно, в итоге функциональность пострадала, а плюсов не видно.

1. Запретили переустанавливать потому что ссылка должна себя вести как объект. В частности, "o1 = o2" должно копировать объект. Т.е., для переустановки ссылки должен быть отдельный синтаксис. Кроме того, подобная "жесткость" позволяет проще читать код - примерно как запрет break в циклах в некоторых языках ;) Если нужно что-то менять  по ходу - всегда есть указатели.
2. Плюсы:
- отсутствие звездочек и стрелочек (самый очевидный)
- перегрузка операторов (ради нее все и затевалось, насколько я помню). Т.е., "p1 + p2" перегрузить нельзя.
- Можно использовать соглашение, по которому ссылка - это ненулевой указатель. Очень удобно, потому что убирает кучу проверок указателя на ноль (код чище) - ссылка никогда не может быть нулевой. И без жутких шаблонов. Единственный недостаток - в отличие от нормального ненулевого указателя ссылку нельзя переинитить, да (но на этот случай можно обратиться к жутким шаблонам).

Berserker

  • Sr. Member
  • ****
  • Сообщений: 254
    • Просмотр профиля
Re: C++ инициализация ссылок
« Ответ #10 : Март 15, 2013, 06:04:36 pm »
Но согласитесь, Влад, не так уж сложно было ввести нечто вроде:

set TObj &ref = another_obj;

Цена-то — одно ключевое слово и минимальные изменения в компиляторе.

DddIzer

  • Гость
Re: C++ инициализация ссылок
« Ответ #11 : Март 15, 2013, 06:19:29 pm »
Но согласитесь, Влад, не так уж сложно было ввести нечто вроде:

set TObj &ref = another_obj;

Цена-то — одно ключевое слово и минимальные изменения в компиляторе.
Проблема ИМХО в другом.. Алексей богомерзким примером засандаливает ссылку на локальную переменную определенную в  функции foo() - лично я до такого не опускался... и не уверен,  что это гуд... и даже не знал, что такое возможно... :), век живи век учись... однако.

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: C++ инициализация ссылок
« Ответ #12 : Март 15, 2013, 06:25:10 pm »
Но согласитесь, Влад, не так уж сложно было ввести нечто вроде:

set TObj &ref = another_obj;

Цена-то — одно ключевое слово и минимальные изменения в компиляторе.
Проблема ИМХО в другом.. Алексей богомерзким примером засандаливает ссылку на локальную переменную определенную в  функции foo() - лично я до такого не опускался... и не уверен,  что это гуд... и даже не знал, что такое возможно... :), век живи век учись... однако.
Во-первых это не локальная переменная, а возвращаемое значение (то что было в моем примере).
Во-вторых это да, полностью безопасно и полностью легально в языке (этот кейс явно прописан в стандарте).
Y = λf.(λx.f (x x)) (λx.f (x x))

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: C++ инициализация ссылок
« Ответ #13 : Март 15, 2013, 06:30:55 pm »
Но согласитесь, Влад, не так уж сложно было ввести нечто вроде:

set TObj &ref = another_obj;

Цена-то — одно ключевое слово и минимальные изменения в компиляторе.
Цена будет огромна.

Весь смысл ссылок в том, что их нет.

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

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

SET ИмяВарПараметра = another_object;

Ведь в компиляторе всего пару строк изменить :-)
Y = λf.(λx.f (x x)) (λx.f (x x))

DddIzer

  • Гость
Re: C++ инициализация ссылок
« Ответ #14 : Март 15, 2013, 06:32:11 pm »

Во-первых это не локальная переменная, а возвращаемое значение (то что было в моем примере).
Во-вторых это да, полностью безопасно и полностью легально в языке (этот кейс явно прописан в стандарте).
Не совсем так... значение это есть ЗНАЧЕНИЕ.. ,адрес ПЕРЕМЕННОЙ есть адрес...  я говорю про то, что вы не  можете же
сделать  int  & b=456; ... а тут аналогично присваивается ЧТО? впрочем если этот случай рассматривается отдельно.. почему бы и нет..., только стройности языку это не прибавляет...