Смотрю тут один код, повсеместно для указателей, которые могут указывать на объект, а могут не указывать никуда, применен boost::optional. Скажите, а чем такой подход лучше чем просто хранение NULL в указателе, если в данный момент он ни на что не указывает? Ведь проверять-то все равно надо, когда необходимо получить оттуда сам объект.
Здравствуйте, Аноним, Вы писали:
А>Смотрю тут один код, повсеместно для указателей, которые могут указывать на объект, а могут не указывать никуда, применен boost::optional. Скажите, а чем такой подход лучше чем просто хранение NULL в указателе, если в данный момент он ни на что не указывает? Ведь проверять-то все равно надо, когда необходимо получить оттуда сам объект.
boost::optional хранит объект внутри себя, а не в куче, как указатель.
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, Аноним, Вы писали:
А>>Смотрю тут один код, повсеместно для указателей, которые могут указывать на объект, а могут не указывать никуда, применен boost::optional. Скажите, а чем такой подход лучше чем просто хранение NULL в указателе, если в данный момент он ни на что не указывает? Ведь проверять-то все равно надо, когда необходимо получить оттуда сам объект.
J>boost::optional хранит объект внутри себя, а не в куче, как указатель.
из плюсов я бы назвал в первую очередь понятность кода (семантику). например, глядя на это:
не очень очевидно, что может вернуть `get_some()`, в то время как глядя на `get_other_some()` сразу понятно, что возвращает значения он не всегда.
еще больше информации можно получить если правильно назвать эти функции... например так: `try_get_some()`. в этом случае имя как бы намекает, что get может и не получиться... остается за кадром, что будет если таки не получится: исключение (этого тут вообще не видно) или nullptr в качестве результата.
Здравствуйте, Аноним, Вы писали:
А>Смотрю тут один код, повсеместно для указателей, которые могут указывать на объект, а могут не указывать никуда, применен boost::optional. Скажите, а чем такой подход лучше чем просто хранение NULL в указателе, если в данный момент он ни на что не указывает? Ведь проверять-то все равно надо, когда необходимо получить оттуда сам объект.
Я думаю дело вкуса.
Имеем T* vs optional< T* >
T*
+ легко обращаться к объекту
— нужно не забывать инициализировать.
optional< T* > val
— громозкий доступ val.get()->some,
+ само инициализируется
+ вариант что нужно на самом деле различать отсутствие объекта, и нулевой объект
Здравствуйте, Аноним, Вы писали:
А>Смотрю тут один код, повсеместно для указателей, которые могут указывать на объект, а могут не указывать никуда, применен boost::optional. Скажите, а чем такой подход лучше чем просто хранение NULL в указателе, если в данный момент он ни на что не указывает? Ведь проверять-то все равно надо, когда необходимо получить оттуда сам объект.
boost::optional<T>, или boost::optional<T*>
В первом случае имеем объект, или не имеем объект.
Во втором случае имеем указатель (который указывает на объект, или на его отсутствие), или не имеем указателя вообще. Это отличается от просто указателя, очевидно.
Так-то телепатов нет, пример давай. Может по делу, а может из-за недопонимания.
Z>не очень очевидно, что может вернуть `get_some()`, в то время как глядя на `get_other_some()` сразу понятно, что возвращает значения он не всегда.
Вкусовщина. Лично мне очевидно, что если в качестве возвращаемого значения задан указатель, то он может быть и нулевым, если, конечно, в документации специально не оговорено иное. С другой стороны, насколько я помню (смотреть лень, да-с) "пустой" boost::optional при попытке разыменовать его гарантированно выкинет исключение, а вот разыменование нулевого указателя — формально, UB. Правда, насколько мне известно, на любой платформе, где существует бюст, разыменование нулевого указателя дает ошибку доступа к памяти и завершение приложения.
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Здравствуйте, flаt, Вы писали:
F>Не совсем корректно сравнивать T* и optional<T*>, который по семантике уже как T**.
Да, чего то я не то вечером написал , тогда остается
T* vs optional< T >
T*
— нужно не забывать инициализировать.
optional< T >
+ само инициализируется
Здравствуйте, slava_phirsov, Вы писали:
_>Вкусовщина. Лично мне очевидно, что если в качестве возвращаемого значения задан указатель, то он может быть и нулевым, если, конечно, в документации специально не оговорено иное. С другой стороны, насколько я помню (смотреть лень, да-с) "пустой" boost::optional при попытке разыменовать его гарантированно выкинет исключение, а вот разыменование нулевого указателя — формально, UB. Правда, насколько мне известно, на любой платформе, где существует бюст, разыменование нулевого указателя дает ошибку доступа к памяти и завершение приложения.
Нет там исключения, но асерт помогает.
// Returns a reference to the value if this is initialized, otherwise,
// the behaviour is UNDEFINED
// No-throw
reference_const_type get() const { BOOST_ASSERT(this->is_initialized()) ; return this->get_impl(); }
Здравствуйте, Igore, Вы писали:
I>Нет там исключения
Зря я, конечно, поленился посмотреть. Но вообще странно — бюст, да вдруг без исключения обошлись? Это они недоработали
I>
I>// Returns a reference to the value if this is initialized, otherwise,
I>// the behaviour is UNDEFINED
I>// No-throw
I>reference_const_type get() const { BOOST_ASSERT(this->is_initialized()) ; return this->get_impl(); }
I>
Ну вот как бы что assert при попытке получить несуществующее значение, что segmentation fault при попытке разыменовать нулевой "голый" указатель — хрен перца не слаще.
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Здравствуйте, slava_phirsov, Вы писали:
_>Но вообще странно — бюст, да вдруг без исключения обошлись? Это они недоработали
По моему, вполне согласовывается с остальными бустовыми библиотеками. В смысле, есть возможность проверить присутствует значение или нет. И есть доступ без "дополнительных издержек".
Здравствуйте, slava_phirsov, Вы писали:
_>разыменование нулевого указателя — формально, UB. Правда, насколько мне известно, на любой платформе, где существует бюст, разыменование нулевого указателя дает ошибку доступа к памяти и завершение приложения.
во-первых это фактически UB. т.е. компилятор может оптимизировать код исходя из допущений что при разыменовении указатель не пустой.
во-вторых на x86 разыменование нулевого указателя приводит к аппаратному исключению, и некоторые ОС/компиляторы позволяют его перехватить и обработать.
A>во-первых это фактически UB. т.е. компилятор может оптимизировать код исходя из допущений что при разыменовении указатель не пустой.
Пример такой оптимизации?
A>во-вторых на x86 разыменование нулевого указателя приводит к аппаратному исключению, и некоторые ОС/компиляторы позволяют его перехватить и обработать.
Почему-то даже не хочется вспоминать кэпа. Позволяет перехватить и обработать — и что? Старый добрый, сто раз заданный вопрос: перехватили, как обрабатывать будем? Вот, для определенности, под *nix перехвачен сигнал SEGV: что делаем (с примером кода)?
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Здравствуйте, slava_phirsov, Вы писали:
A>>во-первых это фактически UB. т.е. компилятор может оптимизировать код исходя из допущений что при разыменовении указатель не пустой.
_>Пример такой оптимизации?
http://coliru.stacked-crooked.com/a/88872e0375f755f0
A>>во-вторых на x86 разыменование нулевого указателя приводит к аппаратному исключению, и некоторые ОС/компиляторы позволяют его перехватить и обработать.
_>Почему-то даже не хочется вспоминать кэпа. Позволяет перехватить и обработать — и что? Старый добрый, сто раз заданный вопрос: перехватили, как обрабатывать будем? Вот, для определенности, под *nix перехвачен сигнал SEGV: что делаем (с примером кода)?
я хз что за сигналы у вас в никсах, но в винде можно написать
и это будет вполне нормально работать.
я видел игровой сервер со средним аптаймом около месяца,
там был похожий код, несколько раз в месяц там ловились #AV, но все прекрасно работало — никакие данные не терялись.
многабукаф можешь тезисно изложить? Своими словами. Не могу вкурить, честно.
A>я хз что за сигналы у вас в никсах
Собственно с этого надо было начинать
A>но в винде можно написать
A>
A>for (;;) {
A> __try {
A> f();
A> } __except (log_exception()) {}
A>}
A>
A>и это будет вполне нормально работать. A>я видел игровой сервер со средним аптаймом около месяца, A>там был похожий код, несколько раз в месяц там ловились #AV, но все прекрасно работало — никакие данные не терялись.
Что мешало сделать приложение службой, которая тупо вылетает по Segmentation Fault, а затем перезапускается? Желание похвастаться, что оно крутится целый месяц до перезапуска?
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
if (!p) return never_called_function(); // dead code, shall be eliminated
и он мертвый, компилятор его выкидывает потому что перед ним написано *p
_>Что мешало сделать приложение службой, которая тупо вылетает по Segmentation Fault, а затем перезапускается? Желание похвастаться, что оно крутится целый месяц до перезапуска?
то что при падении приложения теряются все данные в RAM?
то что при вызове terminate не вызываются деструкторы? "раскрутка стека" — может слышал что-то?
Здравствуйте, Abyx, Вы писали:
A>что непонятно-то? там есть код A>
A>if (!p) return never_called_function(); // dead code, shall be eliminated
A>
A>и он мертвый, компилятор его выкидывает потому что перед ним написано *p
Собственно к природе указателей это имеет слабое отношение. С таким же успехом компилятор будет оптимизировать такое:
inline void foo(int bar)
{
if (!bar)
baz();
}
foo(1); // скорее всего соптимизируется до пустого места
A>то что при падении приложения теряются все данные в RAM?
Точно так же они потеряются если уборщица шнур питания шваброй выдернет. Проблема целостности данных решается совсем другими методами.
A>то что при вызове terminate не вызываются деструкторы?
Зачем тебе при завершении приложения вызов деструкторов?
A>"раскрутка стека" — может слышал что-то?
Без комментариев.
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Здравствуйте, Abyx, Вы писали:
_>>Что мешало сделать приложение службой, которая тупо вылетает по Segmentation Fault, а затем перезапускается? Желание похвастаться, что оно крутится целый месяц до перезапуска? A>то что при падении приложения теряются все данные в RAM? A>то что при вызове terminate не вызываются деструкторы? "раскрутка стека" — может слышал что-то?
Рекомендую по этому поводу почитать Спинеллиса, "Идеальная архитектура" — там на примере игровой инфраструктуры Darkstar описывается, как нужно решать подобные задачи.
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Здравствуйте, slava_phirsov, Вы писали:
_>>>Что мешало сделать приложение службой, которая тупо вылетает по Segmentation Fault, а затем перезапускается? Желание похвастаться, что оно крутится целый месяц до перезапуска? A>>то что при падении приложения теряются все данные в RAM? A>>то что при вызове terminate не вызываются деструкторы? "раскрутка стека" — может слышал что-то?
_>Рекомендую по этому поводу почитать Спинеллиса, "Идеальная архитектура" — там на примере игровой инфраструктуры Darkstar описывается, как нужно решать подобные задачи.
я в курсе как решать эти задачи.
я просто привел пример того как обработка #AV успешно работала в реальном проекте (который писался в начале нулевых и не мной)
Здравствуйте, slava_phirsov, Вы писали:
_>>>Что мешало сделать приложение службой, которая тупо вылетает по Segmentation Fault, а затем перезапускается? Желание похвастаться, что оно крутится целый месяц до перезапуска? A>>то что при падении приложения теряются все данные в RAM? A>>то что при вызове terminate не вызываются деструкторы? "раскрутка стека" — может слышал что-то?
_>Рекомендую по этому поводу почитать Спинеллиса, "Идеальная архитектура" — там на примере игровой инфраструктуры Darkstar описывается, как нужно решать подобные задачи.
UB означает, что компилятор может оптимизировать код по своему усмотрению. И он будет по максимуму оптимизировать.
Z>>не очень очевидно, что может вернуть `get_some()`, в то время как глядя на `get_other_some()` сразу понятно, что возвращает значения он не всегда.
_>Вкусовщина. Лично мне очевидно, что если в качестве возвращаемого значения задан указатель, то он может быть и нулевым, если, конечно, в документации специально не оговорено иное. С другой стороны, насколько я помню (смотреть лень, да-с) "пустой" boost::optional при попытке разыменовать его гарантированно выкинет исключение, а вот разыменование нулевого указателя — формально, UB. Правда, насколько мне известно, на любой платформе, где существует бюст, разыменование нулевого указателя дает ошибку доступа к памяти и завершение приложения.
Люди не любят проверять возвращаемое значение и часто это делают. Пример, функция malloc, её результат очень часто забывают проверить.
А вот с optional такое уже не прокатит.
Здравствуйте, alzt, Вы писали:
A>Люди не любят проверять возвращаемое значение и часто это делают. Пример, функция malloc, её результат очень часто забывают проверить. A>А вот с optional такое уже не прокатит.
Как тут где-то выше говорилось, если malloc вернет тебе NULL, а ты, не глядя, попытаешься его разыменовать, на PC ты получишь ошибку сегментации и приложение тупо вылетит. Если не проверишь optional — получишь вылет по BOOST_ASSERT. Разница? Вообще-то никакой.
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Здравствуйте, Аноним, Вы писали:
А>Смотрю тут один код, повсеместно для указателей, которые могут указывать на объект, а могут не указывать никуда, применен boost::optional. Скажите, а чем такой подход лучше чем просто хранение NULL в указателе, если в данный момент он ни на что не указывает? Ведь проверять-то все равно надо, когда необходимо получить оттуда сам объект.
Лучше тем что явно выражает намерение. Как я могу узнать глядя на сигнатуру метода, что возвращаемый указатель может быть NULL и это валидное поведение (т.е. мне нужно писать if( ptr ) а не assert( ptr )? Только заглянув в имплементацию. boost::optional позволяет избежать этих лишних телодвижений и явно говорит о том что пустое возвращаемое значение не является нарушением инварианта.
Здравствуйте, antropolog, Вы писали:
A>Лучше тем что явно выражает намерение. Как я могу узнать глядя на сигнатуру метода, что возвращаемый указатель может быть NULL и это валидное поведение (т.е. мне нужно писать if( ptr ) а не assert( ptr )? Только заглянув в имплементацию. boost::optional позволяет избежать этих лишних телодвижений и явно говорит о том что пустое возвращаемое значение не является нарушением инварианта.
И ещё тем, что не предполагает полиморфизм, и предполагает монопольное/эстафетное владение