На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
Страницы: (2) 1 [2]  все  ( Перейти к последнему сообщению )  
> двухшаговая инициализация
    ЫукпШ, не не не ... тут еще есть одна сторона вопроса. Вот ты спроси Килю "что ты больше всего любишь в своей жизни?". Он тебе ответит - RAII. Кстати - смарт-поинтеры из того же балета "Леблядиное Озеро". Да идея - супер, да удобно использование. Но не нужно расслабляться, ибо есть еще одна неприятная сторона жысти и программирования. Есть "нестабильные" ресурсы. Объясняю на пальцах...

    1) Запилили в RAII обертку указатель на выделенную память - супер, и нет проблем
    2) Запилили в RAII обертку хендл на файл, вроде все пучком. Одна незадача - файл оказался сетевым, и дворник обоссал маршрутизатор

    Вот второй вариант, когда ресурсы могут менять свое состояние по внешним факторам - тут засада. Да, можно попытаться бороться (типа запилить коллбэк на разрыв сети), но не всегда это доступно в юзер-моде.

    Вывод: как RAII, так и смарт-поинтерами нужно пользоваться с оглядкой на ситуацию и прогнозы. Они замечательны - но не панацея от всех бед!
      Цитата JoeUser @
      Вывод: как RAII, так и смарт-поинтерами нужно пользоваться с оглядкой на ситуацию и прогнозы. Они замечательны - но не панацея от всех бед!

      О чём это ?
      я не предлагаю следить за выделением/освобождением ресурса.
      Пишем свой смарт-поинтер. Задача которого следить
      за операцией "if(ptr)".
      Например:
      Скрытый текст

      ExpandedWrap disabled
        // --------------------------------------------------------------------------
        // FILE SPTR.h 2020.08.05
        // --------------------------------------------------------------------------
        // класс - указатель
        // --------------------------------------------------------------------------
        #ifndef __SPTR_20200805_H
        #define __SPTR_20200805_H
        // --------------------------------------------------------------------------
        template<class T>
        class SPTR
        {
         public:
         
         private:
         
         protected:
                     T    *ptr;
         
         public:
                     WINAPI SPTR(void);
                     WINAPI ~SPTR(void);
         
                T*   WINAPI operator ->(void) const;
              void   WINAPI operator = (T *ptr_);
                T&   WINAPI operator * (void) const;
        // операции преобразования типа
                     WINAPI operator T * (void) const;
         
                     WINAPI operator bool ();
        };
        // --------------------------------------------------------------------------
        template <class T>
        WINAPI SPTR<T>::SPTR(void) : ptr (NULL)
        {
        }
        // --------------------------------------------------------------------------
        template<class T>
        WINAPI SPTR<T>::~SPTR(void)
        {
        }
        // --------------------------------------------------------------------------
        template <class T> WINAPI SPTR<T>::operator bool ()
        {
         ::OutputDebugString(_T(__FUNCTION__));
        //..
        // вот тут можно возбудить исключительную ситуацию
        //..
         if(ptr)  return true;
         else     return false;
        }
        // --------------------------------------------------------------------------
        template <class T>
        void WINAPI SPTR<T>::operator = (T *ptr_)
        {
         ptr = ptr_;
        }
        // --------------------------------------------------------------------------
        template<class T>T& WINAPI SPTR<T>::operator *(void)const
        {
         return *ptr;
        }
        // --------------------------------------------------------------------------
        template<class T>T* WINAPI SPTR<T>::operator->(void)const
        {
         return ptr;
        }
        // --------------------------------------------------------------------------
        template<class T> WINAPI SPTR<T>::operator T* (void)const    
        {
         return ptr;
        }  
        // --------------------------------------------------------------------------
        #endif

      Сообщение отредактировано: ЫукпШ -
        Цитата JoeUser @
        Вот второй вариант, когда ресурсы могут менять свое состояние по внешним факторам - тут засада.
        Ресурс, который не твой, не твой ресурс, не так ли? Почему я пишу очевиднейшие вещи не в Холиварах?..
          Цитата Qraizer @
          Ресурс, который не твой, не твой ресурс, не так ли?

          Ну да ... а как быть с такими вот "неотдаваемыми" ресурсами? Твой вариант?
            Тебе нужен ресурс, но у тебя нет возможности им владеть – это значит, что у тебя нет ресурса, поэтому любая операция с ним потенциально может провалиться. В общем случае вариантов, кроме как аварийно завершить работу, не существует. За примером, когда иначе просто никак, далеко ходить не надо: когда ты ждёшь мьютекс на WaitForSingleObject(), например, а тебе в ответ WAIT_ABANDONED. С одной стороны мьютекс свободен, с другой – он освободился не в результате окончания транзакции по переходу охраняемой сущности в другое состояние, а значит охраняемая им сущность неинвариантна. Причём ты ещё и не знаешь, что именно в ней поломано. Привет всем апологетам TerminateThread(), которые т.о. запросто дропнут нитку посреди HeapAlloc(), например, и что теперь делать остальной части приложения?
            В частных случаях возможны варианты. В твоём примере есть возможность попробовать восстановить контроль над ресурсом. Но вот стоит ли? Обоссанный роутер будет подниматься из небытия куда дольше, чем юзер согласится ждать, наблюдая пред свои ясны очи "реконнектинг, приз вэйт" в твоём приложении. Если решишь, что стоит, ну тогда надо реконнектиться, конечно. Ну... раза три... или пять... Как думаешь, хватит или таки мало?
            Можно и других примеров привести. Типа исчерпанного места на диске, где просто попросить юзера освободить местечко, и дать добро на повтор... или лучше указать другое место, куда попробовать записать неписанное... или может быть лучше заранее предусмотреть себе место и зарезервировать, чтоб такой ситуации просто не должно было никогда происходить, как думаешь? А иначе просто ругаться, мол, дай места, а то работать не буду и не запускаться вовсе.
            Теория говорит, что если ты не знаешь хорошего решения возможной проблемы по умолчанию, не надо и пытаться ничего реализовывать, кинь экспешн, и пусть его ловит, обрабатывает и предпринимает действия по устранению тот слой кода, который знает. Вопрос лишь в грамотном проекте архитектуры твоего ПО, чтоб каждый слой был ответственен за свои задачи и звал интерфейсы других слоёв для их решения. Если спроектируешь неудобно, никакие паттерны не сделают приятно, всё равно будет винегрет из зависимостей, а вместо дерева интерфейсов ненаправленный граф. А в удобной архитектуре внезапно оказывается, что RAII вполне в неё вливается.
            Практика пробовала юзать т.н. возобновляемые отказы, когда вместо размотки стека можно предпринять действия по устранению причины отказа и просто продолжить, как ни в чём ни бывало. В SEH это вообще испокон веку было возможно. Я иногда пользовался, было интересно пощупать, но это всё было на синтетике. А на реальной практике ни разу. Вот что по этому пишет товарищ Страуструп в своём труде "Дизайн и эволюция языка C++"
            Цитата 16.6. Возобновление или завершение?
            При проектировании механизма обработки исключений наиболее спорным оказался вопрос, следует ли поддержать семантику возобновления или прекращения исполнения. Иными словами, может ли обработчик исключения потребовать возобновления исполнения с того момента, где было возбуждено исключение?
            ...
            Поначалу я думал так: «Почему бы и нет? Ведь сразу видно несколько ситуаций, в которых я мог бы воспользоваться возобновлением». Но в последующие четыре года моя точка зрения некоторым образом изменилась, и потому механизм обработки исключений в языке C++ поддерживает так называемую модель с завершением.
            Главные споры по поводу возобновления и завершения разгорелись в комитете ANSI C++. Вопрос обсуждался и на заседаниях всего комитета, и в рабочей группе по расширениям, и на вечерних технических обсуждениях, и в списках для рассылки по электронной почте. Споры продолжались с декабря 1989 г., когда был сформирован комитет ANSI C++, до ноября 1990 г. Тема вызвала большой интерес и у всего сообщества пользователей C++.
            ...
            Затем, на заседании в Пало Альто в ноябре 1991 г. мы услышали блестящий доклад Джима Митчелла (Jim Mitchell), работавшего в компании Sun, а перед этим – в Xerox PARC. Доклад содержал доводы в пользу семантики завершения, подкрепленные личным опытом и фактическими данными. На протяжении 20 лет Митчелл пользовался обработкой исключений в разных языках и на первых порах отстаивал семантику возобновления в качестве одного из главных проектировщиков и разработчиков системы Cedar/Mesa от компании Xerox. Его вывод звучал так:
            Цитата
            «Завершение следует предпочесть возобновлению. Это вопрос не вкуса, а многолетней практики. Возобновление выглядит соблазнительно, но это порочный метод».

            Свое утверждение Митчелл подкрепил рассказом о работе над несколькими операционными системами. Самым главным был пример системы Cedar/Mesa, которую написали программисты, любившие и умевшие пользоваться семантикой возобновления. Однако через десять лет в системе из полумиллиона строк остался лишь один случай использования возобновления – в запросе контекста. Поскольку и в данной ситуации оно фактически было не нужно, механизм возобновления исключили полностью, после чего скорость работы этой части системы значительно возросла. Во всех тех случаях, когда применялась операция возобновления (а это более десяти лет эксплуатации), появлялись определенные проблемы и приходилось искать более подходящий механизм. По сути дела, все применения возобновления были связаны с неумением отделить друг от друга различные уровни абстракции.
            Советую почитать 16.6 целиком, там много текста, с тезисами, историческими фактами, анализом и выводами.

            Если очень хочется попробовать попользовать возобновление при отказах, никто тебе не мешает передавать функтор в нижние слои кода. Попробуй. Может быть твои случаи тоже окажутся такими, каковые я тут называю странными.
            Сообщение отредактировано: Qraizer -
              Ну ок, сенкс, идею понял.

              Цитата Qraizer @
              Вот что по этому пишет товарищ Страуструп в своём труде "Дизайн и эволюция языка C++"

              Да, надо будет почитать. Тут, в принципе, "внеязыковой" вопрос.
                Цитата Qraizer @
                Привет всем апологетам TerminateThread(), которые т.о. запросто дропнут нитку посреди HeapAlloc(), например, и что теперь делать остальной части приложения?

                Такие существуют? :unsure:
                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                0 пользователей:


                Рейтинг@Mail.ru
                [ Script execution time: 0,0326 ]   [ 16 queries used ]   [ Generated: 28.03.24, 12:00 GMT ]