Документ был изменён. Сохранить изменения?

Хакер дает советы, раскрывает секреты и делится своими мыслями по поводу программирования.

Модератор: Хакер

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Документ был изменён. Сохранить изменения?

Сообщение Хакер » 09.05.2008 (Пт) 22:25

Вы ведь наверняка делали когда-либо такой запрос к пользователю в своих программах. А если и не делали, то ведь, согласитесь, когда-нибудь настанет время, и такой запрос надо будет сделать.

Рассмотрим типичный пример:
Код: Выделить всё
Select MsgBox(..., ..., vbYesNoCancel)
  Case vbYes
     SaveAllFiles
  Case vbCancel
     Cancel = True
     Exit Sub
  End Select
  TerminateApplication
End Select


Думаю понятно, что в рамках этого примера функция SaveAllSettings сохраняет изменения в файлах, а TerminateApplication - окончательно завершает приложение.

И кажется вполне логичным, что обработчик vbNo не реализован. В нём был бы только TerminateApplication, но тогда и в vbYes надо было бы ставить TerminateApplication. А здесь программист вынес TerminateApplication за пределы Select'а, а обработчик случая vbNo просто не создал (потому как после вынесения из него вызова TerminateApplication, там попросту ничего бы не осталось).

Это красивый код? Нет. Отстойный код.

Дело в том, что хоть это и ужасно маловероятно, но всё-таки возможно (особенно при нехватке памяти -- такое происходит постоянно), что вызов MsgBox'а обломится где-то внутри (конкретно - где-то внутри MessageBox'а), и никакого окна сообщения не появится, и функция сразу же вернёт нам 0. (Поверьте, при нехватке памяти, скорее всего, никакой ошибки Out of memory не будет: MessageBox вернёт MsgBox'у ноль и MsgBox послушно нам этот 0 возвратит).

Теперь давайте посмотрим, как поведёт наш код себя в такой ситуации:

Вызывается MsgBox, но из-за сбоя, сообщение не создаётся, юзер ничего не замечает, сразу же возвращается 0.

0 сравнивается с vbYes. Т.к. 0 не равен vbYes первый Case не срабатывает.
0 сравнивается с vbCancel. Т.к. 0 так же не равен vbCancel, второй Case тоже не срабатывает.

SelectCase заканчивается. Вызывается функция TerminateApplication - приложение тихо закрывается.

А теперь ещё представим, как это будет смотреться со стороны пользователя:

Чел наоткрывал кучу приложений, таким образом, что возникла катастрофическая нехватка памяти. Чел открыл блокнот и написал в нём довольно важный текст (номер счёта, к примеру, который ему продиктовали по телефону). Чел лезет мышкой нажать на крестик, ожидая, что появится привычный вопрос, что он нажмёт "Да", сохранит файл, после чего блокнот автоматом закроется. Но как только чел жмёт на крестик - блокнот с шумом (вызвать MessageBeep памяти всё же должно хватить) закрывается. Без всяких вопросов. Вместе с номером банковского счёта.

Действительно, неприятная ситуация?

Поэтому, вывод: Всегда пишите так, чтобы сбои внешних функций нанесли минимальный ущерб вашей программе и, главное, данным, с которыми она работает (они зачастую намного ценнее, чем программа).

В данном случае, наиболее безопасным вариантом был бы следующий:
Код: Выделить всё
Select MsgBox(..., ..., vbYesNoCancel)
  Case vbYes
     SaveAllFiles
  Case vbNo
  Case Else
      Cancel = True
      Exit Sub
  End Select
  TerminateApplication
End Select



________________

Я могу с уверенностью сказать, что этот подход используется в продуктах MS. Поэтому с Блокнотом, в действительности, ничего страшного не произойдёт. В то время как многие программы (особенно это касается ненавидимого мною Svoi.NET PHP Edit'а ) если им не хватит чего-нибудь (памяти там, или совести) отобразить диалог с вопросом - тупо закрываются.

Для всякого рода запросов к пользователю этот принцип можно сформулировать так:
Если вы задаёте вопрос пользователю на тему совершить ли какое-либо опасное действие или не совершать, следует проверять ответ "Да" и совершать только в этом случае и не совершать во остальных, а не наоборот.

Т.е. если речь идёт о вопросе "Удалить выбранный файл", надо делать так:
Код: Выделить всё
If PromptForDelete() = Yes Then
    Kill
Else
    DontKill
End if


а ни в коем случае не так:

Код: Выделить всё
If PromptForDelete() = No Then
    DontKill
Else
    Kill
End if
.

По этой же самой причине, создавая константы, подобные тем, что содержатся в энуме vbMsgBoxResult, надо всегда стараться давать значение 0 нейтральному элементу. Чтобы факт возврата функцией нуля не был случайно воспринят как согласие на какое-то потенциально-опасное необратимое действие.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

SLIM
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1840
Зарегистрирован: 04.04.2008 (Пт) 18:21
Откуда: Краснодар

Сообщение SLIM » 10.05.2008 (Сб) 11:32

Дело в том, что хоть это и ужасно маловероятно, но всё-таки возможно

Вот вот. У меня ни разу не было. Да и у кого было то. Кто пишет такие громоздкие проэкты, что памяти невероятно не хватает.
Пишите жизнь на чистовик.....переписать не удастся.....

ACiD
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 261
Зарегистрирован: 10.12.2005 (Сб) 2:29
Откуда: г. Санкт - Петербург

Сообщение ACiD » 10.05.2008 (Сб) 11:55

SLIM писал(а):Вот вот. У меня ни разу не было. Да и у кого было то. Кто пишет такие громоздкие проэкты, что памяти невероятно не хватает.
Ага, значит не веришь, вот тебе подтверждение http://www.libo.ru/libo794.html :twisted:

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 10.05.2008 (Сб) 11:58

Кто пишет такие громоздкие проэкты, что памяти невероятно не хватает.

Нет. У тех, кто любит держать открытыми 19 окон броузера, фотошоп, 3 экземпляра VB, 1 экземпляр VS.2003, Winamp, 10 окон ICQ, и 10 блокнотов.

У меня, к примеру :)

Когда наблюдаеются вот такие спецэффекты:
http://share.fire-lines.ru/hacker/hbug2.png
http://share.fire-lines.ru/hacker/img_handle_bug.png (обратите внимание на отсутсвие строки меню в окнах IE)
http://share.fire-lines.ru/hacker/bug_hoverflow_gs.png
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

BV
Thinker
Thinker
Аватара пользователя
 
Сообщения: 3987
Зарегистрирован: 12.09.2004 (Вс) 0:55
Откуда: Молдавия, г. Кишинёв

Сообщение BV » 10.05.2008 (Сб) 18:03

Вы ведь наверняка делали когда-либо такой запрос к пользователю в своих программах.


Да, вот так:

Код: Выделить всё
Private Sub Form_Unload(Cancel As Integer)
    If FileSaved = 0 Then Cancel = True
    '...
End Sub

Private Function FileSaved() As Long
    If CFI.bChanged Then
        Dim mResult As VbMsgBoxResult
        mResult = MsgBox("Save changes to " & IIf(CFI.strGlobalFileName <> vbNullString, _
            GetTitle(GetObjectName(CFI.strGlobalFileName)), APP_DEFAULTFILETITLE) & "?", _
            vbYesNoCancel Or vbExclamation Or vbApplicationModal, APP_NAME)
        Select Case mResult
            Case vbYes
                Call SaveFile
                FileSaved = 1
            Case vbNo
                FileSaved = 2
            Case vbCancel
                FileSaved = 0
        End Select
    Else
        FileSaved = -1
    End If
End Function


Дело в том, что хоть это и ужасно маловероятно, но всё-таки возможно (особенно при нехватке памяти -- такое происходит постоянно), что вызов MsgBox'а обломится где-то внутри (конкретно - где-то внутри MessageBox'а), и никакого окна сообщения не появится


Если постоянно учитывать такие возможности, то разработка даже относительно простых программ растянется на многие годы, а сами программы станут тяжелыми и их код трудночитаемым.

Кроме того, при нехватке памяти такое поведение программ вполне логично. Пускай юзер побеспокоится об увеличени памяти и/или файла подкачки.

Вообще, сколько у тебя памяти? У меня 1 ГБ + 1.5 файла подкачки, мне хватает. Никаких аномалий под XP при запущенной VS 2008 + Winamp 5 + Opera/Firefox + Miranda/QIP Infium + TC + MS Word 2007 + Notepad++ + несколько окон проводника + GIMP.

Нет. У тех, кто любит держать открытыми 19 окон броузера, фотошоп, 3 экземпляра VB, 1 экземпляр VS.2003, Winamp, 10 окон ICQ, и 10 блокнотов.


Сколько раз я тебе говорил, поставь Оперу, Миранду и прикупи памяти -- наступит тебе счастье. Да, и оцени Notepad++.

Когда наблюдаеются вот такие спецэффекты:

Вот так взял, и спалил свою аську с мэйл-агентом... смело, смело...
Последний раз редактировалось BV 11.05.2008 (Вс) 15:10, всего редактировалось 1 раз.
const char *out = "|*0>78-,+<|"; size_t cc = char_traits<char>::length(out);
for (size_t i=0;i<cc;i++){cout<<static_cast<char>((out[i]^89));}cout<<endl;

ANDLL
Великий гастроном
Великий гастроном
Аватара пользователя
 
Сообщения: 3450
Зарегистрирован: 29.06.2003 (Вс) 18:55

Сообщение ANDLL » 10.05.2008 (Сб) 20:31

Знаете, у меня то же когда запущен ie, проводник и VS2008 хватает памяти, даже при том что озу у меня всего лишь 2 Гб
Гастрономия - наука о пище, о ее приготовлении, употреблении, переварении и испражнении.
Блог

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 10.05.2008 (Сб) 22:53

Если постоянно учитывать такие возможности, то разработка даже относительно простых программ растянется на многие годы, а сами программы станут тяжелыми и их код трудночитаемым.

Не соглашусь с тобой.
Во-первых, если говорить исключительно о вышеописанном примере, то код стал лишь на строчку длиннее, но зато насколько наждёжнее.
Во-вторых, я же не призываю сидеть "с увеличительным стеклом" и обследовать свою программу, выявляя и исправляя в обязательном порядке все места, которые с вероятностью один к миллиону дадут сбой. Однако, об опасных местах всё-же следует побеспокоиться.

Кроме того, при нехватке памяти такое поведение программ вполне логично. Пускай юзер побеспокоится об увеличени памяти и/или файла подкачки.

Всегда можно махнуть рукой на что-то и сказать, а пусть, вон, юзер об этом беспокоится. Юзер конечно пусть беспокоится, но с другой стороны, во-первых, если при возникновении критической ситуации программа выстоит, в то время как остальные -- рухнут, это будет только плюсом этой программе, а её производителю можно будет только выразить респект. А во-вторых, не лишним будет поставить себя на место юзера, потерявшего что-то важное и ощутить ту степень досады, которую человек при этом испытывает. Разве не здорово будет уменьшить вероятность возникновения таких неприятностей?

Вот так взял, и спалил свою аську с мэйл-агентом... смело, смело

Не вижу ни одной причины скрывать их. Чего там может быть секретного? Вот скажи.


И да, ещё. Вкладки меня бесят. А памяти у меня 1 гб, сколько pagefil'а - не помню.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Amed
Алфизик
Алфизик
 
Сообщения: 5346
Зарегистрирован: 09.03.2003 (Вс) 9:26

Сообщение Amed » 11.05.2008 (Вс) 0:02

Rambler-icq = :puker: !

:)

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 11.05.2008 (Вс) 0:07

Amed писал(а):Rambler-icq = :puker: !

+1

Но QIP у меня не запустился, а Миранда мне не понравилась.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

keks-n
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2509
Зарегистрирован: 19.09.2005 (Пн) 17:17
Откуда: г. Москва

Сообщение keks-n » 11.05.2008 (Вс) 14:08

Миранду надо просто правильно настроить. В том виде, что на сайте и в кустарных сборках оно неудобоваримо.
Изображение

BV
Thinker
Thinker
Аватара пользователя
 
Сообщения: 3987
Зарегистрирован: 12.09.2004 (Вс) 0:55
Откуда: Молдавия, г. Кишинёв

Сообщение BV » 11.05.2008 (Вс) 15:21

Однако, об опасных местах всё-же следует побеспокоиться.


Вот так бы и сказал в своем посте, что речь идет об опасных местах.

Но QIP у меня не запустился, а Миранда мне не понравилась.


Чем Миранда тебе не понравилась?
const char *out = "|*0>78-,+<|"; size_t cc = char_traits<char>::length(out);
for (size_t i=0;i<cc;i++){cout<<static_cast<char>((out[i]^89));}cout<<endl;

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 11.05.2008 (Вс) 15:53

BV
Во втором тезисе так и говорится.


Не могу сказать, что чем-то конкретно. Помню, что не понравилась смайлами, способом, которым отображается переписка (сообщения ввиде блоков с границами). И точно чем-то ещё...
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

keks-n
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2509
Зарегистрирован: 19.09.2005 (Пн) 17:17
Откуда: г. Москва

Сообщение keks-n » 11.05.2008 (Вс) 21:52

Хакер
Смайлов существует несколько комплектов, вид сообщений вообще меняется нараз - количество скинов давно перевалило за тысячу.
Изображение

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 11.05.2008 (Вс) 21:54

Не важно. Как бы там ни было, вещи, не отсносящиеся к теме мы здесь обсуждать не будем :)
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Krasavica
Небожительница
Небожительница
Аватара пользователя
 
Сообщения: 1378
Зарегистрирован: 04.11.2003 (Вт) 17:51
Откуда: Россия, город-герой Москва ;-)

Сообщение Krasavica » 26.05.2008 (Пн) 23:33

Хакер писал(а):...
Когда наблюдаеются вот такие спецэффекты:
http://share.fire-lines.ru/hacker/hbug2.png

Какой интересный значок в статусе у Рея :)
я - ангел!!! ...просто крылья в стирке, а нимб на подзарядке!
Меня трудно найти, легко потерять и невозможно забыть.Изображение


Вернуться в МануAll

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3

    TopList