Форум программистов, компьютерный форум CyberForum.ru

Интересная инициализация ссылки - C++

Восстановить пароль Регистрация
 
Gorillych
14 / 14 / 1
Регистрация: 04.07.2013
Сообщений: 76
06.07.2013, 22:06     Интересная инициализация ссылки #1
Доброго времени суток.
Рассмотрим вот такой код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Base
{
public:
    Base(Base *instance, 
         unsigned int NumElems):
      vec(NumElems),
      vec_ref(instance->vec)
    {}
    std::vector<float> vec;
    std::vector<float>& vec_ref;
};
 
class Der : public Base
{
public:
    Der() : Base(nullptr, 5){}
};
Эта штука вполне удачно компилируется, однако, смущает то, как инициализируется ссылка vec_ref в конструкторе - ссылка ведь не может быть NULL как указатель. Получается, что в конструкторе Base происходит нечто вроде nullptr->vec. Так что же в данном случае представляет собой vec_ref после инициализации и насколько безопасен такой код?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
06.07.2013, 22:06     Интересная инициализация ссылки
Посмотрите здесь:

C++ интересная головоломка
Интересная сортировка C++
C++ Интересная сортировка
C++ Интересная головоломка
C++ Интересная задачка
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
06.07.2013, 22:09     Интересная инициализация ссылки #2
это код с неопределенным поведением и скорее всего крашем.
синтаксически все верно. но в рантайме начнутся проблемы, т.к. тут попытка обратится к члену какого-то объекта через нулевой указатель.
Gorillych
14 / 14 / 1
Регистрация: 04.07.2013
Сообщений: 76
06.07.2013, 22:11  [ТС]     Интересная инициализация ссылки #3
DU, lда, это я уже проверил - дамп памяти получился. но если не обращаться к этому элементу, то все вроде бы ок. я вот хотел бы уточнить, не чревато ли это утечками какими-нибудь, если код оставить как есть, но не обращаться к элементу vec_ref, инициализированному как показано выше?
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4237 / 2770 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
06.07.2013, 22:12     Интересная инициализация ссылки #4
Цитата Сообщение от Gorillych Посмотреть сообщение
ссылка ведь не может быть NULL как указатель
Нет, так и в коде этого тоже нет.
Цитата Сообщение от Gorillych Посмотреть сообщение
Получается, что в конструкторе Base происходит нечто вроде nullptr->vec.
Ну да, ссылка на вектор инициализируется вектором. Что не так?
Цитата Сообщение от Gorillych Посмотреть сообщение
насколько безопасен такой код?
Не на сколько, он же в рантайме сломается
Gorillych
14 / 14 / 1
Регистрация: 04.07.2013
Сообщений: 76
06.07.2013, 22:14  [ТС]     Интересная инициализация ссылки #5
Цитата Сообщение от Kastaneda Посмотреть сообщение
Не на сколько, он же в рантайме сломается
сломается, только если к этой ссылке обратиться
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4237 / 2770 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
06.07.2013, 22:17     Интересная инициализация ссылки #6
Цитата Сообщение от Gorillych Посмотреть сообщение
сломается, только если к этой ссылке обратиться
а nullptr->vec не смущает?
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11849 / 6828 / 773
Регистрация: 27.09.2012
Сообщений: 16,930
Записей в блоге: 2
Завершенные тесты: 1
06.07.2013, 22:17     Интересная инициализация ссылки #7
Gorillych, Ссылка безопаснее лишь тем, что не может быть не инициализированной, но никто не запрещает инмциализировать ее не верными данными
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
06.07.2013, 22:19     Интересная инициализация ссылки #8
ну есть негласное правило, когда лучше ссылки использовать, а когда указатели.
если ваш класс может корректно работать в случае, когда ему передадут нулевой указатель (типа специально предусмотрена такая возможность для какого-нибудь там дефолтного поведения) - то передаем в него указатель.
если не может (в вашем случае - не может. т.к. внутренний член инициализируется членом, получаемым от переданного в конструктор объекта), то тут лучше воспользоваться ссылкой, т.к. ссылки вроде как как всегда ссылаются на какой-то объект. "вроде как" - это не всегда так, но в этом случае ответственность на вызывающей стороне. она должна следить, чтобы в конструктор приходила ссылка на существующий объект. т.о., использование ссылки вместо указателя намекает вызывающей стороне что сюда нужно отдавать что-то существующее, иначе сам дурак.
Gorillych
14 / 14 / 1
Регистрация: 04.07.2013
Сообщений: 76
06.07.2013, 22:34  [ТС]     Интересная инициализация ссылки #9
Croessmah, жаль, лучше бы уж компилятор ругался в таких случаях

Добавлено через 11 минут
Цитата Сообщение от Kastaneda Посмотреть сообщение
а nullptr->vec не смущает?
смущает, конечно) поэтому и тему создал

Добавлено через 3 минуты
DU, если vec_ref будет не ссылкой, а указателем, от этого что-то принципиально изменится в рантайме?
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4237 / 2770 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
06.07.2013, 22:38     Интересная инициализация ссылки #10
Цитата Сообщение от Gorillych Посмотреть сообщение
смущает, конечно) поэтому и тему создал
Так оно сломается в момент обращения по nullptr, т.е. еще до инициализации ссылки.

Добавлено через 45 секунд
Цитата Сообщение от Gorillych Посмотреть сообщение
если vec_ref будет не ссылкой, а указателем, от этого что-то принципиально изменится в рантайме?
нет, просто в этом случае оно упадет в момент инициализации указателя, а не в момент инициализации ссылки
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
06.07.2013, 22:44     Интересная инициализация ссылки #11
нет. не будет. ссылки и указатели транслируются компилятором в один и тот же бинарный код.

на счет сломается - не факт. поскольку Obj* obj = &superOjbPtr->obj - это не изменяющее обращение.
т.к. компилятор знает, смещение в памяти объекта obj относительно объекта superObj и в данном случае мы получаем указатель на obj, то компилятор может просто сгенерировать код obj = superObjPtr + смещение = 0 + смещение. т.е. тут арифметика указателей вполне может оказаться так, что ничего не случится. а вот при попытке изменить obj за счет вызова какого-нибудь метода или просто изменить, если это какой-нибудь инт, вот тут будут проблемы, т.к. obj указывает хз куда.
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4237 / 2770 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
06.07.2013, 22:52     Интересная инициализация ссылки #12
Цитата Сообщение от DU Посмотреть сообщение
компилятор может просто сгенерировать код obj = superObjPtr + смещение = 0 + смещение.
Ну да, так оно и будет, только адрес получится очень маленьким (если только смещение не равно паре гигов ), а в современных десктопных ОСях это тоже недопустимо. Может под какое-нибудь специфичное устройство со специфичной ОСью это и будет работать (всмысле не скрэшится), но винда и линукс на х86 выкинут исключение.

P.S. хотя замечание в целом верное, я что-то неподумав написал.
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
06.07.2013, 22:55     Интересная инициализация ссылки #13
вот тестик в 2012 студии. инициализация через нулевой указатель не крашится. крашится попытка изменения.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
 
struct Struct
{
  int structMember;
};
 
struct SuperStruct
{
  char offset[8];
  Struct str;
};
 
int main()
{
  SuperStruct* superStruct = nullptr;
  Struct* structPtr = &superStruct->str;
  Struct& structRef = superStruct->str;
  std::cout << "address of struct = 0x" << structPtr << std::endl;
  std::cout << "address of struct = 0x" << &structRef << std::endl;
//  structRef.structMember = 5; // runtime error.
  return 0;
}
output:
address of struct = 0x00000008
address of struct = 0x00000008
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4237 / 2770 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
06.07.2013, 22:56     Интересная инициализация ссылки #14
Цитата Сообщение от DU Посмотреть сообщение
а вот при попытке изменить obj за счет вызова какого-нибудь метода или просто изменить. если это какой-нибудь инт, вот тут будут проблемы, т.к. obj указывает хз куда.
Да, верно. Вот это
Цитата Сообщение от Kastaneda Посмотреть сообщение
но винда и линукс на х86 выкинут исключение.
я писал опять не думая У меня в голове картина по другому выглядела (там почему-то было obj = *(0 + offset))
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
06.07.2013, 23:00     Интересная инициализация ссылки #15
Цитата Сообщение от Gorillych Посмотреть сообщение
ссылка ведь не может быть NULL как указатель.
Может. Но стать NULL она не может, а только быть изначально. И поменяться может только NULL ссылка.
Gorillych
14 / 14 / 1
Регистрация: 04.07.2013
Сообщений: 76
06.07.2013, 23:29  [ТС]     Интересная инициализация ссылки #16
Всем большое спасибо за ответы.
В целом, предыстория вопроса такова. Такая конструкция используется для моделирования последовательности объектов конвейерного типа. v_ref - это входные данные в узел, полученные от предыдущего узла, v - выходное данные текущего узла, полученные как результат обработки v_ref. Таким образом, самый первый узел в очереди не имеет v_ref как результат работы предыдущего узла, т.е. ни на что не ссылается и не обрабатывается. Дело в том, что приведенный в начале темы код писался не мной. Лично я бы написал нечто подобное:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Base
{
public:
    Base(Base *instance, 
         unsigned int NumElems):
      vec(NumElems),
      vec_ref(instance==nullptr?  nullptr : &instance->vec)
    {}
    std::vector<float> vec;
    std::vector<float>* vec_ref;
};
 
class Der : public Base
{
public:
    Der() : Base(nullptr, 5){}
};
т.е. вместо ссылки был бы указатель - так понятнее. Но предыдущими разрабами реализовано именно через ссылку. Так вот я просто хотел выяснить, есть ли в этом какой-нибудь сакральный смысл, или это просто "индусский код"?
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
06.07.2013, 23:32     Интересная инициализация ссылки #17
Нет, это дешёвая русская подделка.
Gorillych
14 / 14 / 1
Регистрация: 04.07.2013
Сообщений: 76
06.07.2013, 23:34  [ТС]     Интересная инициализация ссылки #18
Цитата Сообщение от taras atavin Посмотреть сообщение
Нет, это дешёвая русская подделка.
Я Ваш юмор не очень понял.
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
06.07.2013, 23:37     Интересная инициализация ссылки #19
Ну настоящие индусы делают более тупые ошибки, так что это не индусский код, а очень кривая его русская имитация.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
06.07.2013, 23:38     Интересная инициализация ссылки
Еще ссылки по теме:

Интересная штука C++
C++ Массивы, интересная задача!
C++ Интересная конструкция в C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Gorillych
14 / 14 / 1
Регистрация: 04.07.2013
Сообщений: 76
06.07.2013, 23:38  [ТС]     Интересная инициализация ссылки #20
taras atavin, теперь понял)
Yandex
Объявления
06.07.2013, 23:38     Интересная инициализация ссылки
Ответ Создать тему
Опции темы

Текущее время: 17:34. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru