Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 19.12.2016, 19:56   #1
Sheogorath
 
Регистрация: 15.03.2015
Сообщений: 5
По умолчанию Всегда ли обнуляется указатель?

Здравствуйте!

Есть такой код:
Код:
int *pVal;
try
{
pVal = nullptr;
pVal = new int;
}
catch (bad_alloc &ba)
{
delete pVal;
cout << ba.what();
}
Вопрос состоит в следующем: всегда ли будет обнуляться указатель pVal перед вызовом операции new?. То есть, может ли компилятор оптимизировать код (возможно при каких-то особых настройках оптимизации) таким образом, что перед попыткой выделения памяти операцией new не произойдёт обнуление указателя?
Sheogorath вне форума Ответить с цитированием
Старый 19.12.2016, 20:13   #2
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,709
По умолчанию

Я бы даже сказал, что в большинстве случаев данный код выкинется. Т.к. старое значение не используется и сразу перезатирается.
p51x вне форума Ответить с цитированием
Старый 19.12.2016, 20:29   #3
Sheogorath
 
Регистрация: 15.03.2015
Сообщений: 5
По умолчанию

Хм, операция new может сгенерировать исключение. В этом случае переменная pVal не будет перезатёрта, а значит, если компилятор выкинет инициализацию нулём, то pVal будет содержать случайное значение. Следовательно попытка вызова delete в блоке catch может закончиться очень плохо ((

Таким образом, возможна ситуация, когда старое значение не перезатирается и используется. Компилятор это не учтёт и всё равно выкинет обнуление переменной??
Sheogorath вне форума Ответить с цитированием
Старый 19.12.2016, 20:56   #4
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,709
По умолчанию

Вы в катч попадаете, если у нью все плохо. Зачем там делит делать?
p51x вне форума Ответить с цитированием
Старый 19.12.2016, 21:43   #5
Sheogorath
 
Регистрация: 15.03.2015
Сообщений: 5
По умолчанию

Да, Вы правы, в данном конкретном случае delete внутри catch не нужен. Я написал его там просто для примера. Дело не в delete, дело в том, что старое значение переменной, которое, якобы не используется и будет выкинуто компилятором, на самом деле использоваться может.
Если компилятор не выбросит инициализацию указателя нулём, то вызов delete в блоке catch будет безопасен, а если выбросит, то delete будет применяться к неинициализированному указателю. Неужели компилятор это не учитывает?
Sheogorath вне форума Ответить с цитированием
Старый 19.12.2016, 23:21   #6
Son Of Pain
Участник клуба
 
Регистрация: 23.12.2010
Сообщений: 1,129
По умолчанию

Компилятор может оптимизировать как угодно до тех пор, пока не меняется наблюдаемое поведение программы (as-if rule). У этого правила есть только пара исключений - компилятор может убирать некоторые вызовы конструктора копирования (copy elision), и некоторые выделения памяти (начиная с С++14).

В приведенном примере кода оптимизация очевидно влияет на наблюдаемое поведение: внутри обработчика catch мы можем увидеть неинициализированное значение, хотя в коде оно инициализируется.

Следовательно, компилятор может убрать присваивание тогда и только тогда, когда он на 100% гарантирует, что вызов new не бросит эксепшн. Тобишь в реальной жизни практически никогда.
Son Of Pain вне форума Ответить с цитированием
Старый 19.12.2016, 23:25   #7
Croessmah
Вредный кошак
Участник клуба
 
Аватар для Croessmah
 
Регистрация: 14.10.2012
Сообщений: 1,159
По умолчанию

Цитата:
Сообщение от Son Of Pain Посмотреть сообщение
Компилятор может оптимизировать как угодно
Наверное, стоит упомянуть, хоть это и не в тему,
что любое неопределенное поведение
он также может оптимизировать как угодно.
Croessmah вне форума Ответить с цитированием
Старый 20.12.2016, 00:14   #8
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,709
По умолчанию

Цитата:
Следовательно, компилятор может убрать присваивание тогда и только тогда, когда он на 100% гарантирует, что вызов new не бросит эксепшн. Тобишь в реальной жизни практически никогда.
Включите оптмизацию и из try присваивание пропадет... другое дело, что компилятор заметит delete и перенесет присваивание в catch.
p51x вне форума Ответить с цитированием
Старый 20.12.2016, 11:28   #9
Croessmah
Вредный кошак
Участник клуба
 
Аватар для Croessmah
 
Регистрация: 14.10.2012
Сообщений: 1,159
По умолчанию

Цитата:
Сообщение от p51x Посмотреть сообщение
Включите оптмизацию и из try присваивание пропадет... другое дело, что компилятор заметит delete и перенесет присваивание в catch.
В коде ТС неизвестен контекст, поэтому однозначно сказать сможет ли компилятор оптимизировать код невозможно.
Например, если я перегружу operator new так, чтобы он выбрасывал не bad_alloc, то компилятор не сможет переместить присваивание в секцию catch, также, как и не сможет удалить его. Хотя он способен инициализировать нулем переменную сразу, потому как, между объявлением и присваиванием больше ничего не делается с данной переменной.
Croessmah вне форума Ответить с цитированием
Старый 21.12.2016, 01:13   #10
Sheogorath
 
Регистрация: 15.03.2015
Сообщений: 5
По умолчанию

Ясно, всем спасибо за помощь.
Sheogorath вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Не обнуляется таймер почему-то... FleXik Общие вопросы Delphi 5 13.04.2014 17:54
Обнуляется переменная Leonid183 Visual C++ 0 27.10.2011 16:06
Обнуляется переменная Hippie Помощь студентам 1 09.01.2010 20:22
Socket обнуляется переменнaя KoBRaAndrey Работа с сетью в Delphi 4 06.01.2010 21:30
Всегда позади и всегда впереди в одном приложении Legat Win Api 4 27.10.2007 15:48