Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.75/4: Рейтинг темы: голосов - 4, средняя оценка - 4.75
Gorillych
15 / 15 / 3
Регистрация: 04.07.2013
Сообщений: 76
#1

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

06.07.2013, 22:06. Просмотров 759. Ответов 19
Метки нет (Все метки)

Доброго времени суток.
Рассмотрим вот такой код:
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 после инициализации и насколько безопасен такой код?

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

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
06.07.2013, 22:06
Ответы с готовыми решениями:

Зачем нужны rvalue ссылки, если есть универсальные ссылки
Читаю книгу Скотта Мэйерса... Что-то я совсем запутался с этими rvalue...

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

Интересная головоломка
1.С помощью текстового редактора создать файл который содержит текст.Длина ряда...

Интересная конструкция в C++
Добрый день. Подскажите пожалуйста, что это такое: float time =...

Интересная конструкция
хотелось бы уточнить по поводу int(*a)(); это массив указателей на ф-ии (an...

19
DU
1486 / 1132 / 164
Регистрация: 05.12.2011
Сообщений: 2,279
06.07.2013, 22:09 #2
это код с неопределенным поведением и скорее всего крашем.
синтаксически все верно. но в рантайме начнутся проблемы, т.к. тут попытка обратится к члену какого-то объекта через нулевой указатель.
1
Gorillych
15 / 15 / 3
Регистрация: 04.07.2013
Сообщений: 76
06.07.2013, 22:11  [ТС] #3
DU, lда, это я уже проверил - дамп памяти получился. но если не обращаться к этому элементу, то все вроде бы ок. я вот хотел бы уточнить, не чревато ли это утечками какими-нибудь, если код оставить как есть, но не обращаться к элементу vec_ref, инициализированному как показано выше?
0
Kastaneda
Jesus loves me
Эксперт С++
4763 / 2966 / 342
Регистрация: 12.12.2009
Сообщений: 7,531
Записей в блоге: 2
Завершенные тесты: 1
06.07.2013, 22:12 #4
Цитата Сообщение от Gorillych Посмотреть сообщение
ссылка ведь не может быть NULL как указатель
Нет, так и в коде этого тоже нет.
Цитата Сообщение от Gorillych Посмотреть сообщение
Получается, что в конструкторе Base происходит нечто вроде nullptr->vec.
Ну да, ссылка на вектор инициализируется вектором. Что не так?
Цитата Сообщение от Gorillych Посмотреть сообщение
насколько безопасен такой код?
Не на сколько, он же в рантайме сломается
0
Gorillych
15 / 15 / 3
Регистрация: 04.07.2013
Сообщений: 76
06.07.2013, 22:14  [ТС] #5
Цитата Сообщение от Kastaneda Посмотреть сообщение
Не на сколько, он же в рантайме сломается
сломается, только если к этой ссылке обратиться
0
Kastaneda
Jesus loves me
Эксперт С++
4763 / 2966 / 342
Регистрация: 12.12.2009
Сообщений: 7,531
Записей в блоге: 2
Завершенные тесты: 1
06.07.2013, 22:17 #6
Цитата Сообщение от Gorillych Посмотреть сообщение
сломается, только если к этой ссылке обратиться
а nullptr->vec не смущает?
0
Croessmah
++Ͻ
14365 / 8147 / 1533
Регистрация: 27.09.2012
Сообщений: 20,079
Записей в блоге: 3
Завершенные тесты: 1
06.07.2013, 22:17 #7
Gorillych, Ссылка безопаснее лишь тем, что не может быть не инициализированной, но никто не запрещает инмциализировать ее не верными данными
0
DU
1486 / 1132 / 164
Регистрация: 05.12.2011
Сообщений: 2,279
06.07.2013, 22:19 #8
ну есть негласное правило, когда лучше ссылки использовать, а когда указатели.
если ваш класс может корректно работать в случае, когда ему передадут нулевой указатель (типа специально предусмотрена такая возможность для какого-нибудь там дефолтного поведения) - то передаем в него указатель.
если не может (в вашем случае - не может. т.к. внутренний член инициализируется членом, получаемым от переданного в конструктор объекта), то тут лучше воспользоваться ссылкой, т.к. ссылки вроде как как всегда ссылаются на какой-то объект. "вроде как" - это не всегда так, но в этом случае ответственность на вызывающей стороне. она должна следить, чтобы в конструктор приходила ссылка на существующий объект. т.о., использование ссылки вместо указателя намекает вызывающей стороне что сюда нужно отдавать что-то существующее, иначе сам дурак.
0
Gorillych
15 / 15 / 3
Регистрация: 04.07.2013
Сообщений: 76
06.07.2013, 22:34  [ТС] #9
Croessmah, жаль, лучше бы уж компилятор ругался в таких случаях

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

Добавлено через 3 минуты
DU, если vec_ref будет не ссылкой, а указателем, от этого что-то принципиально изменится в рантайме?
0
Kastaneda
Jesus loves me
Эксперт С++
4763 / 2966 / 342
Регистрация: 12.12.2009
Сообщений: 7,531
Записей в блоге: 2
Завершенные тесты: 1
06.07.2013, 22:38 #10
Цитата Сообщение от Gorillych Посмотреть сообщение
смущает, конечно) поэтому и тему создал
Так оно сломается в момент обращения по nullptr, т.е. еще до инициализации ссылки.

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

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

P.S. хотя замечание в целом верное, я что-то неподумав написал.
0
DU
1486 / 1132 / 164
Регистрация: 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
0
Kastaneda
Jesus loves me
Эксперт С++
4763 / 2966 / 342
Регистрация: 12.12.2009
Сообщений: 7,531
Записей в блоге: 2
Завершенные тесты: 1
06.07.2013, 22:56 #14
Цитата Сообщение от DU Посмотреть сообщение
а вот при попытке изменить obj за счет вызова какого-нибудь метода или просто изменить. если это какой-нибудь инт, вот тут будут проблемы, т.к. obj указывает хз куда.
Да, верно. Вот это
Цитата Сообщение от Kastaneda Посмотреть сообщение
но винда и линукс на х86 выкинут исключение.
я писал опять не думая У меня в голове картина по другому выглядела (там почему-то было obj = *(0 + offset))
0
taras atavin
4204 / 1764 / 211
Регистрация: 24.11.2009
Сообщений: 27,565
06.07.2013, 23:00 #15
Цитата Сообщение от Gorillych Посмотреть сообщение
ссылка ведь не может быть NULL как указатель.
Может. Но стать NULL она не может, а только быть изначально. И поменяться может только NULL ссылка.
0
Gorillych
15 / 15 / 3
Регистрация: 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){}
};
т.е. вместо ссылки был бы указатель - так понятнее. Но предыдущими разрабами реализовано именно через ссылку. Так вот я просто хотел выяснить, есть ли в этом какой-нибудь сакральный смысл, или это просто "индусский код"?
0
taras atavin
4204 / 1764 / 211
Регистрация: 24.11.2009
Сообщений: 27,565
06.07.2013, 23:32 #17
Нет, это дешёвая русская подделка.
0
Gorillych
15 / 15 / 3
Регистрация: 04.07.2013
Сообщений: 76
06.07.2013, 23:34  [ТС] #18
Цитата Сообщение от taras atavin Посмотреть сообщение
Нет, это дешёвая русская подделка.
Я Ваш юмор не очень понял.
0
taras atavin
4204 / 1764 / 211
Регистрация: 24.11.2009
Сообщений: 27,565
06.07.2013, 23:37 #19
Ну настоящие индусы делают более тупые ошибки, так что это не индусский код, а очень кривая его русская имитация.
0
Gorillych
15 / 15 / 3
Регистрация: 04.07.2013
Сообщений: 76
06.07.2013, 23:38  [ТС] #20
taras atavin, теперь понял)
0
06.07.2013, 23:38
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
06.07.2013, 23:38

Интересная задачка
#include &lt;iostream&gt; #include &lt;math.h&gt; using namespace std; int main() { ...

Интересная задача
Добрый вечер! если не трудно можете мне помочь с решение задания Шарик...

Интересная сортировка
Дан вектор.Сжать существующий вектор,удалив все отрицательные элементы,не...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru