Недавно был пример какой-то — там автор приводил пример кривого класса, который в примере выводит то, что ожидалось (42 вроде), но баг таки есть. Я (да-да, тёмный человек) что-то не понял, в чем там баг, а спросить по месту не было возможности. Теперь тему потерял, но пробел в знаниях хочется заполнить. Может, автор вспомнит свой пост и разжуёт проблему?
Если вы сохраняете в объекте ссылку, то ваша задача убедиться в том, что ссылка не протухнет за время жизни вашего объекта. А если вы сохраняете константную ссылку, то наступить на эти грабли проще простого:
struct Data {
const int & _i;
explicit Data(const int & i) : _i{i} {}
};
Data d{42}; // Упс! Приплыли.
Проблема в том, что 42 -- это временный экземпляр типа int, фактически это rvalue (или как оно там по стандарту правильно называется).
Но ссылка на rvalue в С++ неявным образом преобразуется к const-ссылке, поэтому в Data уходит константная ссылка на временный объект.
Соответственно, как только завершается выражение, в котором конструктор вызывался, временный объект перестает существовать, а ссылка на него протухает. В Data::_i оказывается повисшая ссылка, это баг.
Начиная с C++11 от этого можно попробовать защититься запретив конструктор, который принимает rvalue references. Что и было показано в том примере.
Но это же C++, здесь на каждую хитрую задницу тут же отыскивается болт с нужной резьбой. В данном случае это вариант шаблона функции std::min от двух аргументов. Этот вариант принимает аргументы по константной ссылке и возвращает так же константную ссылку. При этом если в std::min передать временные объекты, то std::min примет их по константной ссылке и точно так же вернет константную ссылку на один из временных объектов. Со вполне предсказуемым протуханием этой ссылки после завершения выражения, в котором std::min был вызван. Что и позволяет отдать в Data ссылку, которая протухнет сразу же после завершения работы конструктора.
Т.е. пример демонстрирует как вполне себе легальная функция, присутствующая в стандартной библиотеке, позволяет обходить примитивную защиту от ссылок на временные объекты.
А дальше вступают в дело особенности C++, в которых простые int-ы -- это не вполне себе объекты, а хз, особенно в режиме оптимизации, а в самом языке есть UB из-за которых мы вообще не знаем как поведет себя программа при срабатывании UB (в частности, при обращении по протухшей ссылке). Из-за чего протухшая ссылка на временный int при запуске программы может вести себя "вроде бы нормально": в данном случае мы видим вполне ожидаемую печать значения 42.
Но если скомпилировать данный код с санитайзерами, то санитайзер (по крайней мере в GCC) на эту проблему укажет.
Забавно, что вместо int-а мог бы быть какой-то "настоящий" тип, вроде std::string. Но мы все равно могли бы получить вполне ожидаемое поведение в простейших случаях вроде вот такого:
Data d{std::min("A"s, "B"s)};
std::cout << "min is: " << d._i << std::endl;
Тут бы сыграло наличие в std::string т.н. SSO, из-за чего маленькие строки не хранятся в динамической памяти и в d могла бы попасть ссылка на кусок стека, который бы все еще содержал нужное нам значение.
PS. Очень двойственные чувства были по мере написания этого пояснения. С одной стороны, делится знаниями обязательно надо, т.к. сам много чему учишься именно на том, чем делятся другие. Но, с другой стороны, досадно, что дядлы вроде Shmj потянут подобные объяснения в очередную GPT чтобы та натренировалась еще больше и приблизило конец нашей профессии в привычном нам виде.
Re[4]: Не могу найти пример бага, который я не понял
M>>Ага, оно. А в чем там косяк?
S>Если вы сохраняете в объекте ссылку, то ваша задача убедиться в том, что ссылка не протухнет за время жизни вашего объекта. А если вы сохраняете константную ссылку, то наступить на эти грабли проще простого:
S>PS. Очень двойственные чувства были по мере написания этого пояснения. С одной стороны, делится знаниями обязательно надо, т.к. сам много чему учишься именно на том, чем делятся другие. Но, с другой стороны, досадно, что дядлы вроде Shmj потянут подобные объяснения в очередную GPT чтобы та натренировалась еще больше и приблизило конец нашей профессии в привычном нам виде.
Спасибо. Я просто что-то протупил, и не заметил, что там ссыллка в объекте
Здравствуйте, so5team, Вы писали:
S>PS. Очень двойственные чувства были по мере написания этого пояснения. С одной стороны, делится знаниями обязательно надо, т.к. сам много чему учишься именно на том, чем делятся другие. Но, с другой стороны, досадно, что дядлы вроде Shmj потянут подобные объяснения в очередную GPT чтобы та натренировалась еще больше и приблизило конец нашей профессии в привычном нам виде.
Если делать это на русском, то это наступит позже
Здравствуйте, so5team, Вы писали:
S>Если вы сохраняете в объекте ссылку, то ваша задача убедиться в том, что ссылка не протухнет за время жизни вашего объекта. А если вы сохраняете константную ссылку, то наступить на эти грабли проще простого: S>
S>struct Data {
S> const int & _i;
S> explicit Data(const int & i) : _i{i} {}
S>};
S>Data d{42}; // Упс! Приплыли.
S>
О мой бог. Кто-нибудь ещё помнит, с чего вообще начинались ссылки и константность? С того, что они (конечно же, в отличие от ортодоксальных указателей!) делают мир БЕЗОПАСНЕЕ. Да я лучше отчекаю тысячу указателей в ручном режиме, чем буду искать одну вот такую заподлянку.
Говорить, что C++ это язык, где ты можешь отстрелить себе ногу — это большое упрощение. Судя по тому, что люди даже не задаются вопросом, как же мы пришли к такой "безопасности", C++ это язык, где ты трахнешь сам себя в задницу, и даже этого не заметишь.
I'm a sewer mutant, and my favorite authors are Edgar Allan Poo, H.G. Smells and George R.R. Martin.
Re[5]: Не могу найти пример бага, который я не понял
Здравствуйте, Ip Man, Вы писали:
A>> C++ это язык, где ты трахнешь сам себя в задницу, и даже этого не заметишь.
IM>Можно писать аккуратно и всё будет ок. Баг занятный, но скорее как головоломка.
Речь же не об этом. Когда-то нормой была прямая работа с указателями (кстати, так тогда и рассуждали: "писать аккуратно и всё будет ок"). Потом добавили ссылки, затем константность, а ведь всё это дополнительный абстрактный слой, который имеет свою цену в виде усложнения (как и любая дополнительная абстракция). Для чего? Чтобы было безопаснее. Теперь оказывается, что есть тип багов, который возникает только благодаря этому всему. А за что боролись тогда?
То, что я первый и пока единственный об этом спросил, я и сформулировал как "и даже этого не заметишь".
I'm a sewer mutant, and my favorite authors are Edgar Allan Poo, H.G. Smells and George R.R. Martin.
Re[7]: Не могу найти пример бага, который я не понял
Здравствуйте, Alekzander, Вы писали:
A>Потом добавили ссылки, затем константность, а ведь всё это дополнительный абстрактный слой, который имеет свою цену в виде усложнения (как и любая дополнительная абстракция).
И большой у вас опыт программирования на C++ без ссылок и константности? Может вы даже помните в каком году это было?
A>Для чего? Чтобы было безопаснее.
Уверены? Особенно на счет ссылок?
Re[8]: Не могу найти пример бага, который я не понял
Здравствуйте, so5team, Вы писали:
S>И большой у вас опыт программирования на C++ без ссылок и константности? Может вы даже помните в каком году это было?
Вопросы о возрасте считаются неприличными. Но да, большой. На C++ я начал программировать в детстве, а сейчас я далеко не ребёнок.
A>>Для чего? Чтобы было безопаснее.
S>Уверены? Особенно на счет ссылок?
А зачем меня спрашивать? Тут же был недавно задан вопрос, чем ссылки отличаются от указателей — там всё и обсосали. И как (под каким соусом) продавали ссылки массовому программисту я тоже помню.
I'm a sewer mutant, and my favorite authors are Edgar Allan Poo, H.G. Smells and George R.R. Martin.
Re[9]: Не могу найти пример бага, который я не понял
Здравствуйте, Alekzander, Вы писали:
S>>И большой у вас опыт программирования на C++ без ссылок и константности? Может вы даже помните в каком году это было?
A>Вопросы о возрасте считаются неприличными. Но да, большой. На C++ я начал программировать в детстве, а сейчас я далеко не ребёнок.
А по уровню умственного развития и не скажешь. Тем не менее, когда вы успели попрограммировать на C++ без ссылок? Может быть еще до 1985-го года?
A>>>Для чего? Чтобы было безопаснее.
S>>Уверены? Особенно на счет ссылок?
A>А зачем меня спрашивать?
Ну так вы несете пургу, с вас и спрашиваю.
A>И как (под каким соусом) продавали ссылки массовому программисту я тоже помню.
И под каким же? Было ли там что-то про перегрузку операторов, конструкторы копирования?
Re[9]: Не могу найти пример бага, который я не понял
Здравствуйте, Alekzander, Вы писали:
S>>И большой у вас опыт программирования на C++ без ссылок и константности? Может вы даже помните в каком году это было?
A>Вопросы о возрасте считаются неприличными. Но да, большой. На C++ я начал программировать в детстве, а сейчас я далеко не ребёнок.
без ссылок и константности? Правда? Можно на твой код посмотреть?
Здравствуйте, Alekzander, Вы писали:
A>О мой бог. Кто-нибудь ещё помнит, с чего вообще начинались ссылки и константность? С того, что они (конечно же, в отличие от ортодоксальных указателей!) делают мир БЕЗОПАСНЕЕ. Да я лучше отчекаю тысячу указателей в ручном режиме, чем буду искать одну вот такую заподлянку.
Указатель тоже может указывать на временный объект
Здравствуйте, Marty, Вы писали:
A>>О мой бог. Кто-нибудь ещё помнит, с чего вообще начинались ссылки и константность? С того, что они (конечно же, в отличие от ортодоксальных указателей!) делают мир БЕЗОПАСНЕЕ. Да я лучше отчекаю тысячу указателей в ручном режиме, чем буду искать одну вот такую заподлянку.
M>Указатель тоже может указывать на временный объект
Да, в этом паскудном мире, сотканном из лжи, предательства и лицемерия, указатель может содержать невалидный адрес.
А ещё он прямо таки вопиет: я указатель и могу быть невалидным! Всё ли ты проверил? Совпадает ли время жизни?
Любые попытки снять эту проблему — ссылки, умные указатели — не должны создавать новые классы ошибок, связанные с валидностью адресов.
Что касается примеров, оно и видно, как ты в своё время читал MSDN и недавно закрывшийся CodeProject (мир его праху).
I'm a sewer mutant, and my favorite authors are Edgar Allan Poo, H.G. Smells and George R.R. Martin.
Re[7]: Не могу найти пример бага, который я не понял
Здравствуйте, Alekzander, Вы писали:
M>>Указатель тоже может указывать на временный объект
A>Да, в этом паскудном мире, сотканном из лжи, предательства и лицемерия
Есть персонажи, которые считают, что их мнение единственно правильное, но когда с ними пытаешься общаться как со взрослыми людьми, они ведут себя как обиженные на весь мир и избалованные маленькие дети.
Re[8]: Не могу найти пример бага, который я не понял
Здравствуйте, so5team, Вы писали:
A>>Да, в этом паскудном мире, сотканном из лжи, предательства и лицемерия
S>Есть персонажи, которые считают, что их мнение единственно правильное, но когда с ними пытаешься общаться как со взрослыми людьми, они ведут себя как обиженные на весь мир и избалованные маленькие дети.
Поэтому я обычно и не общаюсь с C++ комьюнити
I'm a sewer mutant, and my favorite authors are Edgar Allan Poo, H.G. Smells and George R.R. Martin.