Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.85/13: Рейтинг темы: голосов - 13, средняя оценка - 4.85
148 / 118 / 37
Регистрация: 27.10.2011
Сообщений: 690

Что делать, если "просят" разыменовать null-pointer?

30.09.2015, 10:27. Показов 2676. Ответов 37
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Есть код примерно следующего содержания:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Foo
{
private:
    int *ptr;
 
public:
    int& operator*()
    {
        if (ptr != nullptr)
        {
            ...
        }
        else
        {
            //что делать?
        }
    }
};
Поидее, можно бросить исключение, но вернуть какое то значение мы вроде как обязаны, ибо тип возвращаемого значения - ссылка.
Как обычно на практике обрабатывают такую ситуацию?
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
30.09.2015, 10:27
Ответы с готовыми решениями:

Что делать если XOR пропускает NULL (0-вые) байты
Попробовал зашифровать .rar архив Было: Rar! Пђs Стало:

Разыменовать Pointer
добрового времени суток наткнулся на проблему. как из нетипизированного указателя получить число или строку по типу p: pointer...

Не могу зайти ни в контакт, ни на яндекс, ни на гугл. Везде просят ввести номер. Что делать?
Не могу зайти ни в контакт, ни на яндекс, ни на гугл. Везде просят ввести номер. Что делать? Проверила с помощью Malwarebytes Anti-Malware....

37
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
30.09.2015, 10:40
Nikitko_Cent, Если кидается исключение/assert/terminate/... - ничего мы не должны возвращать. Если же не кидается исключение - лучше использовать optional ну или

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
    int& operator*()
    {
        static int special = -1;
        if (ptr != nullptr)
        {
            ...
        }
        else
        {
            //что делать?
            return optional;
        }
    }
0
148 / 118 / 37
Регистрация: 27.10.2011
Сообщений: 690
30.09.2015, 10:42  [ТС]
Цитата Сообщение от ForEveR Посмотреть сообщение
Nikitko_Cent, Если кидается исключение - ничего мы не должны возвращать.
А что тогда будет, если допустим я кидаю исключение, из вызывающего кода его обрабатываю и всё равно пытаюсь "достучаться" до объекта? Ссылка ведь неразрывно связана с каким-либо объектом
0
183 / 181 / 66
Регистрация: 15.02.2015
Сообщений: 515
30.09.2015, 10:45
Nikitko_Cent, ссылка должна быть сразу инициализирована, т.е. будет объявлена в try {} блоке, если будет брошено исключение, то вы никак не сможете обратиться к этой ссылке
0
529 / 432 / 159
Регистрация: 25.11.2014
Сообщений: 1,662
30.09.2015, 10:50
Цитата Сообщение от Nikitko_Cent Посмотреть сообщение
Ссылка ведь неразрывно связана с каким-либо объектом
Не обязательно. В случае с нулевым указателем, ссылка будет ссылаться на нулевой адрес и там совсем не обязательно какой-то объект и, тем более, твой. Будет ошибка чтения, как вариант.

Добавлено через 2 минуты
Цитата Сообщение от Nikitko_Cent Посмотреть сообщение
Как обычно на практике обрабатывают такую ситуацию?
Возвращают, что есть, например - нулевой адрес.
0
148 / 118 / 37
Регистрация: 27.10.2011
Сообщений: 690
30.09.2015, 11:01  [ТС]
Цитата Сообщение от Velesthau Посмотреть сообщение
Возвращают, что есть, например - нулевой адрес.
Мы же возвращаем ссылку, а не указатель

-----------------------

В общем, что будет при нулевом указателе в таком коде:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
{
    int i;
    Foo foo;
    
    try
    {
        i = *foo;
    }
    catch (...)
    {
        std::cerr << i;
    }
}
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
30.09.2015, 11:05
Лучший ответ Сообщение было отмечено Nikitko_Cent как решение

Решение

Nikitko_Cent,
1) кидать исключение
2) boost::optional
3) null object pattern
4) изменить дизайн. Например, требовать (в документации) вызова функции isValid() у объекта класса перед разыменованием, а внутри оператора поставить assert.
5) изменить дизайн. перепроектировать класс так, чтобы подобная ситуация стала невозможной.
4
183 / 181 / 66
Регистрация: 15.02.2015
Сообщений: 515
30.09.2015, 11:06
Nikitko_Cent, будет выведено значение i, полученное при инициализации (int i; )
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
30.09.2015, 11:07
Цитата Сообщение от Nikitko_Cent Посмотреть сообщение
В общем, что будет при нулевом указателе в таком коде:
Выведется мусор из i. Переменная i в этом коде останется неинициализированной в случае выброса исключения из оператора*.
0
529 / 432 / 159
Регистрация: 25.11.2014
Сообщений: 1,662
30.09.2015, 11:10
Цитата Сообщение от Nikitko_Cent Посмотреть сообщение
Мы же возвращаем ссылку, а не указатель
Ссылка - это и есть адрес. Оно же значение указателя.
0
183 / 181 / 66
Регистрация: 15.02.2015
Сообщений: 515
30.09.2015, 11:18
Velesthau, только ссылка без адреса (без объекта, к которому привязана) не может существовать. Поэтому мы и получим ошибку чтения несуществующего "объекта", которую даже и отловить не сможем.
0
148 / 118 / 37
Регистрация: 27.10.2011
Сообщений: 690
30.09.2015, 11:29  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
Переменная i в этом коде останется неинициализированной в случае выброса исключения
Это по стандарту?

Добавлено через 57 секунд
Цитата Сообщение от DrOffset Посмотреть сообщение
3) null object pattern
А вот это гениально Спасибо

Добавлено через 5 минут
Цитата Сообщение от Velesthau Посмотреть сообщение
Ссылка - это и есть адрес. Оно же значение указателя.
Не соглашусь. Работая с ссылкой, мы не работаем с адресом (как в случае указателя), а работаем с объектом по этому адресу.
Переменная, по определению, это именованная область памяти. Я бы ссылку определил как второе имя этой же самой области памяти
0
30.09.2015, 11:29

Не по теме:

интересно, а что быстрее: проверить валидность указателя или искать метод в vtbl?

0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
30.09.2015, 11:31
Цитата Сообщение от Nikitko_Cent Посмотреть сообщение
Это по стандарту?
И по стандарту и по здравому смыслу.
Вот смотри, даже без ссылок и адресов:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int foo(bool m) 
{
    if(m)
    {
         return 12; 
    }
    throw std::runtime_error("invalid");
}
//..................
 
// случай 1
int i;
 
i = foo(true); // в i - 12, вышли из foo по return
 
// случай 2
int i;
 
i = foo(false); // в i то, что было до вызова функции, т.к. исключение прервало текущий контекст выполнения и до присваивания дело даже не дошло.
1
148 / 118 / 37
Регистрация: 27.10.2011
Сообщений: 690
30.09.2015, 11:34  [ТС]
DrOffset, окей, а что тогда будет вот в таком коде:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
{
    int *i; //заменил на указатель
    Foo foo;
    
    try
    {
        i = &(*foo);
    }
    catch (...)
    {
        std::cerr << *i;
    }
}
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
30.09.2015, 11:37
Цитата Сообщение от Nikitko_Cent Посмотреть сообщение
окей, а что тогда будет вот в таком коде:
В смысле? Я же только что объяснил принцип выше. Будет тоже самое, до присваивания дело не дойдет.
В i будет невалидный адрес (мусор), потому что значение i не было никак задано перед вызовом.. Попытка разыменовать его в catch приведет к неопределенному поведению.
1
148 / 118 / 37
Регистрация: 27.10.2011
Сообщений: 690
30.09.2015, 11:39  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
В смысле? Я же только что объяснил принцип выше. Будет тоже самое, до присваивания дело не дойдет.
В i будет невалидный адрес (мусор), потому что значение i не было никак задано перед вызовом.. Попытка разыменовать его в catch приведет к неопределенному поведению.
Всё, понял-принял. Спасибо
0
529 / 432 / 159
Регистрация: 25.11.2014
Сообщений: 1,662
30.09.2015, 11:59
Цитата Сообщение от Operok Посмотреть сообщение
только ссылка без адреса (без объекта, к которому привязана) не может существовать.
Может. Ссылка с объектом никак не связана. Это просто адрес, любой совершенно.
Цитата Сообщение от Operok Посмотреть сообщение
Поэтому мы и получим ошибку чтения несуществующего "объекта", которую даже и отловить не сможем.
Мы получим эту ошибку, только когда попытаемся обратиться по ссылке.

Добавлено через 11 минут
Цитата Сообщение от Nikitko_Cent Посмотреть сообщение
Работая с ссылкой, мы не работаем с адресом (как в случае указателя)
С точки зрения языка работаем по-разному, а с точки зрения кода int& i = *j; это сделать i псевдонимом значения указателя j.
Цитата Сообщение от Nikitko_Cent Посмотреть сообщение
Переменная, по определению, это именованная область памяти. Я бы ссылку определил как второе имя этой же самой области памяти
Сравни работу
C++
1
2
    int *j = nullptr;
    int i = *j;
и
C++
1
2
    int *j = nullptr;
    int &i = *j;
Обычная переменная, хранящая значение в своей области памяти, упадет на int i = *j;, потому что попытается к себе в область записать значение по адресу j.
Операция с ссылкой int &i = *j; нормально отработает, потому что значение по адресу j ее не интересует здесь. А вот само значение j - да.
0
306 / 101 / 18
Регистрация: 04.07.2014
Сообщений: 571
30.09.2015, 12:53
Цитата Сообщение от Nikitko_Cent Посмотреть сообщение
null object pattern
А вот это гениально
Нет, это не гениально. Даже не просто "не гениально", а ровно наоборот "чрезвычайно скверно". Никогда, просто никогда, не используйте таких подходов как isValid() или NullObject Pattern.
Если в коде что-то подобное появляется, значит нужно написать докладную на архитектора или на преподавателя за профессиональной непригодностью оных.

Если код объектный -- только исключение в такой ситуации.
Либо переходите к функциональному приближению: создавайте отдельную абстракцию разименования, которая может Вам вернуть полиморфный результат, не какой-то NullObject, а полноценный актор, который перенаправит поток исполнения.
Либо вообще откажитесь от объектов и работайте с процедурами и данными на C. Пусть процедура вернёт статус исполнения, а про ссылки забудьте -- работайте с указателями.
0
148 / 118 / 37
Регистрация: 27.10.2011
Сообщений: 690
30.09.2015, 15:57  [ТС]
Цитата Сообщение от mporro Посмотреть сообщение
не используйте таких подходов как isValid() или NullObject Pattern.
Ну с IsValid в принципе понятно, что не так. Но что не так с null-object pattern?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
30.09.2015, 15:57
Помогаю со студенческими работами здесь

Что значит DB-Library Error 10001: NULL DBPROCESS pointer encountered?
Cho snachit etot error msg: DB-Library Error 10001: NULL DBPROCESS pointer encountered

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

Что делать чтоб DataSource у DataGridView не был null?
Добрый день возможно сможете помочь или подсказать, есть код foreach (DataGridViewRow r in dataGridView2.Rows) { ...

При запуске выдает expression stream !=null; что делать?
задача такая: написать прогу, которая будет решать систему линейных уравнений методом гаусса. ошибок при компиляции не выдает, а вот при...

Null pointer
void C_StringBit :: setStrBit() { char* ptr1; cout &lt;&lt; &quot;Введите строку&quot;&lt;&lt; endl; cin &gt;&gt; ptr1; lengthBit = strlen(ptr1); ...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru