|
Вездепух
12930 / 6798 / 1820
Регистрация: 18.10.2014
Сообщений: 17,205
|
||||||
Головоломка для тех, кому под Новый Год нечего делать28.12.2023, 09:07. Показов 5303. Ответов 34
Метки нет (Все метки)
Тема на самом деле уже не раз упоминалась, но тем не менее... Пример кода
p).Головоломка: кто прав согласно спецификации языка?
0
|
||||||
| 28.12.2023, 09:07 | |
|
Ответы с готовыми решениями:
34
Кому скучно и нечего делать, у меня есть нерабочий код Если кому-то нечего делать по выходным в ближайшие полтора года Крестики-нолики. Кому делать нечего научите как исправить ошибку |
|
фрилансер
6447 / 5643 / 1128
Регистрация: 11.10.2019
Сообщений: 15,017
|
||||
| 28.12.2023, 09:31 | ||||
![]() интересный сюжет Добавлено через 1 минуту
а, хотя нет, всё как раз наоборот - сначала присваивание, а потом деструктор по ссылке зануляет указатель. Значит, студия не права
0
|
||||
|
Вездепух
12930 / 6798 / 1820
Регистрация: 18.10.2014
Сообщений: 17,205
|
|||
| 28.12.2023, 09:34 [ТС] | |||
|
Однако, ключевой момент тут как раз в том, что та сущность типа S, которая тут создается - это не временный объект. Если бы параметр функции имел тип const S &s, тогда бы тут действительно создавался временный объект. И, кстати, поведение всех компиляторов было бы одинаковым. Однако в исходном варианте это не временный объект.
0
|
|||
|
фрилансер
6447 / 5643 / 1128
Регистрация: 11.10.2019
Сообщений: 15,017
|
|
| 28.12.2023, 09:40 | |
|
а, то есть, это же S s - локальная переменная внутри функции
но возвращается копия указателя. Затем отрабатывает деструктор, после чего копия должна присвоиться p. И он должен быть таки не нулевой , хм
0
|
|
|
Вездепух
12930 / 6798 / 1820
Регистрация: 18.10.2014
Сообщений: 17,205
|
||
| 28.12.2023, 20:43 [ТС] | ||
|
Параметр функции похож на "локальную переменную" только с точки зрения области видимости идентификатора. Во всех остальных отношениях параметр ведет себя по особому, совсем не как "локальная переменная". Параметры - это не локальные переменные.
0
|
||
|
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
|
||
| 28.12.2023, 21:39 | ||
|
По идее к возвращаемому значению из функции foo может быть применена оптимизация copy elision, а может и нет. Так как может, но необязательно, поэтому каждый из компиляторов может поступать по своему, и каждый будет прав по своему...
0
|
||
|
Вездепух
12930 / 6798 / 1820
Регистрация: 18.10.2014
Сообщений: 17,205
|
||
| 28.12.2023, 21:59 [ТС] | ||
void *. Это вообще обычный скаляр... Как copy elision может повлиять на возвращение скаляра?
0
|
||
|
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
|
|||||||||||
| 28.12.2023, 22:27 | |||||||||||
|
TheCalligrapher,
Наверное правильнее было сказать, что "нет необходимости создавать объект S", так как мы возвращаем значение его поля, которое известно еще до вызова самой функции. Другими словами, функцию foo можно "перефразировать" так:
Добавлено через 55 секунд если будет оптимизация, то получим адрес, если нет, то nullptr
0
|
|||||||||||
|
Вездепух
12930 / 6798 / 1820
Регистрация: 18.10.2014
Сообщений: 17,205
|
||
| 28.12.2023, 22:36 [ТС] | ||
S. То есть что бы тут ни оптимизировал компилятор, игнорировать деструктор S он не имеет права.Поэтому вопрос фактически сводится к: когда, согласно спецификации языка, должен отработать деструктор S?
0
|
||
|
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
|
|||
| 28.12.2023, 22:48 | |||
![]() Но думаю это слишком очевидно, скорее всего есть подвох (если будет время/желание, поищу ответ, интересно)...
0
|
|||
|
Вездепух
12930 / 6798 / 1820
Регистрация: 18.10.2014
Сообщений: 17,205
|
|||
| 28.12.2023, 23:43 [ТС] | |||
p = <результат вызова функции>. Если это легально, то nullptr в p проживет лишь миг, а к моменту вывода в p уже вернется ненулевое значение.
0
|
|||
|
27 / 24 / 4
Регистрация: 20.11.2023
Сообщений: 129
|
|
| 29.12.2023, 08:30 | |
|
По идее s - локальный объект, так что должен быть
nullptr
0
|
|
|
Вездепух
12930 / 6798 / 1820
Регистрация: 18.10.2014
Сообщений: 17,205
|
||
| 29.12.2023, 10:11 [ТС] | ||
|
А вот С++17 внес изменения, которые могут очень сильно подчеркивать отличия параметров от локальных объектов. (В этом, собственно, и заключается ответ на данную головоломку.)
0
|
||
|
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
|
|||
| 29.12.2023, 12:31 | |||
|
Когда мы возвращаем из функции foo указатель s.r, значение указателя присваивается в переменную p в main и казалось бы справедливо ожидать, что p будет ненулевым. Но хитрость в том, что после завершения функции будет вызван деструктор для объекта s, который присвоит в качестве значения для поля r nullptr. Но что такое r? Правильно, это ссылка на переменную p из main. В итоге получается: 1) сначала в main в переменную p будет присвоено значение s.r 2) после присваивания будет вызван деструктор, который сбросит значение переменной p в nullptr по ссылке при этом я допускаю, что п.1 даже не будет выполнен, в силу его бессмысленности в данном случае (т.е возможно будет оптимизация) Добавлено через 14 минут вроде как начиная с С++17, должен сработать copy elision (т.е аргумент будет сконструирован так, что он не будет копироваться из временного)значит объект у нас будет всего один... и раз уж мы возвращаем поле этого единственного объекта, он этот объект не может быть уничтожен прежде чем значение его поля s.r будет записано в переменную p, а значит его деструктор будет вызван после присваивания. в итоге получаем вышеописанный сценарий, 1) запишется адрес в p 2) адрес в p залунился по ссылке
0
|
|||
|
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
|
|
| 29.12.2023, 17:44 | |
|
1
|
|
|
27 / 24 / 4
Регистрация: 20.11.2023
Сообщений: 129
|
||
| 29.12.2023, 18:47 | ||
|
Видимо, те самые правки из C++17 - CWG 1880.
Вот, цитирую:
.Во общем порыскав по стандарту, это единственная более-менее не размытая формулировка. Может, от меня что-то и ускользнуло.
1
|
||
|
Вездепух
12930 / 6798 / 1820
Регистрация: 18.10.2014
Сообщений: 17,205
|
|||||||||||||
| 29.12.2023, 21:04 [ТС] | |||||||||||||
S s - параметра функции foo. Как я уже несколько раз указал в этой теме, объект s во все века и времена, начиная с С++98, создавался и уничтожался на уровень выше - в вызывающей функции main (!). Объект S s - параметр функции foo - на самом деле "принадлежит" функции main и незримо живет именно в функции main, а не в функции foo. И вопрос здесь лишь в том, когда именно этот объект будет уничтожен в функции main.Почему-то этот уголок спецификации языка С++ упорно остается недопонятым и многие считают параметры функции чисто локальными объектами функции, которые якобы создаются и уничтожаются внутри функции. Это не так. Правильную часть текста стандарта (и изменение в С++17) уже процитировали DrOffset и pechka_ne_sed. Да, правильный ответ: оба компилятора правы. Объект S s - параметр функции foo - может быть уничтожен в функции main сразу после возвращения из функции foo (как того требовал стандарт языка вплоть до С++17), а может быть уничтожен намного позже - в конце полного выражения, содержащего вызов функции foo (впервые разрешено в С++17).Это изменение в стандарт было внесено под давлением GCC/Clang (читай: Itanium ABI), которые с начала времен по ряду причин упорно нарушали требования С++98-С++14, продлевая время жизни параметров функций до конца полного выражения. В конечном итоге такое поведение разрешили официально, как implementation-defined выбор из двух вариантов. MSVC++ всегда придерживался "классической" спецификации - все объекты-параметры уничтожаются сразу же после завершения соответствующего вызова функции. S s создавался непосредственно из аргумента p. Все объекты здесь - именованные. Ни одного временного тут нет и никогда не было. Поэтому и copy elision здесь совершенно ни при чем.--- Наглядной и интересной иллюстрацией различия в поведении компиляторов (по первой и по второй модели удаления параметров) являются примеры вот такого рода
foo с параметрами a и b, за жизнью которых можно следить через их уникальные числовые идентификаторы S::id. (Если вы не доверяете этим идентификаторам, то их можно заменить на значение указателя this, но так будет сложнее сравнивать поведение разных запусков и разных компиляторов.)
Именно второй вариант поведения очень хорошо иллюстрирует тот факт, что "локальные параметры" функции на самом деле совсем не локальны - они живут в вызывающем коде. Локальна лишь область видимости идентификаторов таких объектов. Для GCC:
5
|
|||||||||||||
|
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
|
||
| 29.12.2023, 21:05 | ||
|
0
|
||
|
Вездепух
12930 / 6798 / 1820
Регистрация: 18.10.2014
Сообщений: 17,205
|
||
| 29.12.2023, 21:22 [ТС] | ||
|
Да, инициализация параметров при вызове функции делается по модели copy-initialization, то есть параметр S s инициализируется аргументом p так, как будто делалось объявление S s = p;, а "классическая" каноническая семантика такой инициализации сводилась к S s = S(p);. То есть тут действительно мог фигурировать еще и дополнительный временный объект (до эпохи guaranteed copy elision). Однако исходная головоломка относится к современному С++ (С++17 и выше), в котором никакого временного объекта здесь быть не может.
0
|
||
|
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
|
||
| 29.12.2023, 21:36 | ||
|
На мой взгляд это некорректно (наиболее правильный с моей точки зрения вариант развития событий я изложил в #14), и если эта неоднозначность действительно легальна, то её следует выключать по умолчанию и вывести в управление этой "фичей" через флаги компиляции...
0
|
||
| 29.12.2023, 21:36 | |
|
Помогаю со студенческими работами здесь
20
Ищу консультанта/учителя С под Linux, Для тех,кому интересно делиться знаниями Написал программу от делать нечего, она оказалась полезной. А дальше что с ней делать?
Для тех, кому непонятна рекурсия Тест-игра (для тех, кому за 18) Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/
O1rJuneU_ls
https:/ / vkvideo. ru/ video-115721503_456239114
|
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ВВЕДЕНИЕ
Введу сокращения:
аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
|
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi
ветка по-частям.
коммит Create переделка под биомассу. txt
вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
|
Расчёт токов в цепи постоянного тока
igorrr37 05.01.2026
/ *
Дана цепь постоянного тока с сопротивлениями и напряжениями. Надо найти токи в ветвях.
Программа составляет систему уравнений по 1 и 2 законам Кирхгофа и решает её.
Последовательность действий:. . .
|
|
Новый CodeBlocs. Версия 25.03
palva 04.01.2026
Оказывается, недавно вышла новая версия CodeBlocks за номером 25. 03. Когда-то давно я возился с только что вышедшей тогда версией 20. 03. С тех пор я давно снёс всё с компьютера и забыл. Теперь. . .
|
Модель микоризы: классовый агентный подход
anaschu 02.01.2026
Раньше это было два гриба и бактерия. Теперь три гриба, растение.
И на уровне агентов добавится между грибами или бактериями взаимодействий.
До того я пробовал подход через многомерные массивы,. . .
|
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Налог на собак: https:/ / **********/ gallery/ V06K53e
Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf
Пост отсюда. . .
|
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop?
Ниже её машинный перевод.
После долгих разбирательств я наконец-то вернула себе. . .
|