На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
Страницы: (6) [1] 2 3 ...  5 6 все  ( Перейти к последнему сообщению )  
> как скопировать модификатор noexcept в свою функцию?
    Здравствуйте!

    Есть шаблонный класс. В него можно передать любой тип typename ValueType.
    Мне хотелось бы знать, есть ли у этого ValueType для конструктора и др членов, модификатор noexcept.

    Ну... Э... Если очень упростить, то как-то так:
    ExpandedWrap disabled
      template< typename ValueType >
      class someclass
      {
      public:
       
      /* тут я руками вызываю конструктор в моём размещении. */
      void construct() noexcept( noexcept_constructor< ValueType >::value )
      {
      new( &_value ) ValueType();
      }
       
      private:
       
      /* тут, размещается сам объект. */
      char _value[ sizeof( ValueType ) ];
       
      };


    То есть, я хочу скопировать модификатор noexcept для своей функции "construct"
    Если он есть у конструктора ValueType то у меня noexcept( true ), иначе noexcept( false ).
    Это же косается конструкторов копирования, перемещения, операторов копирования, перемещения и деструктора.
    Хорошо бы и для остальных конструкторов и операторов присвоения это получить, да и для произвольных функций тоже.

    Про хидер "type_traits" знаю. Очень внимательно, несколько раз перечитал описание его сущьностей... А вот какой взять, так и не могу выбрать. Чего-то их слишком много!
      is_nothrow_constructible не то?
        Думаю, тебе нужно это.
          Цитата Flex Ferrum @
          Думаю, тебе нужно это.

          Ага. Точно. Читал давно, но неиспользовал и забыл где была фича.


          Вроде, как юзать выражение, я разобрался.
          noexcept( ValueType() )
          Возвращает, инфу о конструкторе, true если он noexcept, иначе false.

          А вот как узнать деструктор, чего-то не понимаю.
          noexcept( ~ValueType() )
          Возвращает false, хотя у меня для проверяемого объекта точно true.
            Батенька, деструкторы всегда nothrow. :)
              Цитата Flex Ferrum @
              Батенька, деструкторы всегда nothrow. :)


              Ннет, не всегда. Есть оговорки. Например одно из предложений для std::expected, чтоб деструктор бросал исключение, если разработчик забыл проверить код ошибки. Но не надо холиваров, ладно?

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

              Во-первых, я накосячил с перекомпиляцией объектных файлов. Поленился в makefile указать зависимость. Ну и прога выдала мне устаревшую инфу.

              Во-вторых, visual studio, оказывается скрыто добавляет для некоторых деструкторов спецификацию noexcept(true). Это можно отключить явно указав noexcept( false ) или ключиком в командной строке.

              Ну и да, noexcept( ~ValueType() ) вернул мне правильную инфу о деструкторе. Вот как в деструкторе проставил true или false, то и вернул.
              Сообщение отредактировано: Eric-S -
                Цитата Eric-S @

                Ннет, не всегда. Есть оговорки. Например одно из предложений для std::expected, чтоб деструктор бросал исключение, если разработчик забыл проверить код ошибки. Но не надо холиваров, ладно?

                Вот без холиваров. А что вообще может означать исключение в деструкторе? Объект нельзя удалить?
                  Цитата Eric-S @
                  char _value[ sizeof( ValueType ) ];

                  К слову, тут тебе ещё надо выравнивание специфицировать корректное.
                    Цитата Олег М @
                    А что вообще может означать исключение в деструкторе? Объект нельзя удалить?

                    Ну, бонально вернуть информацию о возникших проблемах.

                    Для примера, чисто гипотетического, возьмём некую обёртку над хэндлом файла в системе windows.
                    Конструктор файл открывает функцией CreateFile, а деструктор файл закрывает функцией CloseHandle.
                    А функция CloseHandle возвращает код ошибки.

                    Вы меня как-то упрекали за коды возвратов, хотя я как раз предпочитаю бросать исключения, чтоб знать обо всех возникших проблемах.
                    Ну и CloseHandle может вернуть ошибку, которую бросаем в исключении. Причём, именно из деструктора.
                    Это плохо. Это бяка. Но всяко лучше упасть и знать причину падения, чем упасть через std::terminate() и знать, лишь, что где-то случилась проблема.

                    Добавлено
                    Цитата Flex Ferrum @
                    Цитата Eric-S @
                    char _value[ sizeof( ValueType ) ];

                    К слову, тут тебе ещё надо выравнивание специфицировать корректное.

                    У меня сейчас сделано поле в union{ value_type _value };

                    Но про выравнивание, замечание справедливое. Смотрю в сторону std::aligned_storage, но пока не выяснил точно, как его правильно юзать.

                    А у меня, по сабжу, ещё вылез косяк.
                    ExpandedWrap disabled
                        template< typename ...Args >
                        void construct( Args ... args ) noexcept( value_type( args... ) )
                          {
                          new( ADDRESS_OF( this->_value ) ) value_type( args... );
                          }


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

                    Добавлено
                    Цитата Олег М @
                    is_nothrow_constructible не то?

                    Упс. Я разобрался. Действительно, для конструкторов - самое то. Всё получилось очень просто.
                    ExpandedWrap disabled
                        template< typename ...Args >
                        void construct( Args ... args ) noexcept( std::is_constructible< value_type, Args... >::value )
                          {
                          new( ADDRESS_OF( this->_value ) ) value_type( args... );
                          }
                      Цитата Eric-S @
                      noexcept( std::is_constructible

                      Здесь все правильно, именно is_constructible?
                        Цитата Eric-S @
                        Ну и CloseHandle может вернуть ошибку, которую бросаем в исключении. Причём, именно из деструктора.
                        Это плохо. Это бяка. Но всяко лучше упасть и знать причину падения, чем упасть через std::terminate() и знать, лишь, что где-то случилась проблема.


                        На мой взгляд, даже если эта ошибка так крайне необходима, то лучше сохранить её здесь же куда-нибудь в лог и продолжить выполнение деструктора.
                        Иначе получится объект, удалённый наполовину. И что с этим потом делать?
                          Цитата Олег М @
                          Цитата Eric-S @
                          noexcept( std::is_constructible

                          Здесь все правильно, именно is_constructible?

                          Ой, нет... Надо код проверить, неужели я там так же накосячил?...

                          Добавлено
                          И в коде та же бяка. К счастью только в одном месте, в остальных как и положено nothrow.
                          Что-то я вчера поторопился и накосячил. Но хорошо, что заметили.

                          Добавлено
                          Цитата Олег М @
                          На мой взгляд, даже если эта ошибка так крайне необходима, то лучше сохранить её здесь же куда-нибудь в лог и продолжить выполнение деструктора.
                          Иначе получится объект, удалённый наполовину. И что с этим потом делать?

                          Если ошибка в деструкторе, то именно, что сохранять в лог, а затем убивать программу.
                          Ну и да... Запарно лезть в каждый деструктор, чтобы там менять код записи в лог.
                          Я раньше юзал макросы _RPTF и типа того, для записи, но это не совсем то, что хотелось бы.

                          Сейчас, у меня есть класс, где можно зарегистрировать обработчик исключения. Ну, а где-нибудь в деструкторе пишу:
                          ExpandedWrap disabled
                            ~someclass() noexcept( true )
                            {
                            try
                            {
                            ...
                            close_work();
                            ...
                            }
                            catch( ... )
                            {
                            on_exception( std::current_exception() );
                            }
                            }


                          Но это уже моя практика. А так, если не перехватывать, то деструктор, очень даже, может стрельнуть исключением. При этом сработает noexcept, которая вызовет std::terminate() и что вообще сломалось останется долго гадать. При этом раскрутка стека вообще не выполнится.
                            Цитата Eric-S @
                            И в коде та же бяка. К счастью только в одном месте, в остальных как и положено nothrow.
                            Что-то я вчера поторопился и накосячил. Но хорошо, что заметили.


                            Да уж, ошибка хорошая. Не знаю, как в виндах, а в линуксе noexcept выкидывает, при исключении, чёрт знает куда, концов не найдёшь.

                            Добавлено
                            Цитата Eric-S @
                            Сейчас, у меня есть класс, где можно зарегистрировать обработчик исключения. Ну, а где-нибудь в деструкторе пишу:

                            Ну, у меня примерно также. Только я заворачиваю в отдельный try-catch (через макрос) каждую функцию, которая вызывается в деструкторе и может вызвать исключение. Чтобы гарантировать, что они все выполнятся, ну или попытаются выполниться.
                              Цитата Олег М @
                              Да уж, ошибка хорошая. Не знаю, как в виндах, а в линуксе noexcept выкидывает, при исключении, чёрт знает куда, концов не найдёшь.

                              Под виндой, нормально, с моей точки зрения.
                              Сам компилятор visual studio, поддерживает стандартные исключения, через внутренний механизм структурных исключений.
                              Ну а когда прога стреляет исключением, то более менее понятно, откуда оно прилетело.

                              Есть свои заморочки. Под виндой нет удобной трассировки стека в C++. Реализовано через хитрые отладочные функции. Поэтому надо писать свои обёртки и подключать их чудным способом. Зато, в результате, получается очень даже информативно.

                              Так или иначе, даже без отладчика, можно понять, откудо взялось то или иное исключение. Хотя по началу, надо разобраться с механизмом, который не слишком очевиден.

                              Добавлено
                              Цитата Олег М @
                              Ну, у меня примерно также. Только я заворачиваю в отдельный try-catch (через макрос) каждую функцию, которая вызывается в деструкторе и может вызвать исключение. Чтобы гарантировать, что они все выполнятся, ну или попытаются выполниться.

                              Вообще-то и у меня макросы. Для форума их раскрыл, чтоб было нагляднее. У себя пишу
                              ExpandedWrap disabled
                                ~someclass() noexcept( true )
                                {
                                START_EXCEPTION_MONITOR
                                ...
                                STOP_EXCEPTION_MONITOR
                                }


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

                              Уже давно собираюсь сделать отдельные обработчики для каждой нити. Сейчас один обработчик на весь процесс. Но раздумываю, надо оно или нет. Пока делать лень.

                              Добавлено
                              Цитата Олег М @
                              каждую функцию, которая вызывается в деструкторе и может вызвать исключение. Чтобы гарантировать, что они все выполнятся, ну или попытаются выполниться.

                              А вот оборачивать каждую вызываемую функцию... Это... Ну... Изврат уже какой-то. Не, нафиг. Так может чего-нибудь наложится и побочные эффекты замучат. Лучше уж сразу весь деструктор прерывать, на первой же ошибке.

                              А вообще, я стараюсь в деструкторе вызывать только одну функцию. И вообще не писать там сложного кода. Сложный код, должен находится в методах, которые вызывает пользователь. А деструктор, всего лишь подчищает ресурсы.

                              Выше приводил гипотетический пример для обёртки хэндла файла. В деструкторе вызывается только функция CloseHandle.

                              А если уж совсем правильно, то надо примерно так:
                              ExpandedWrap disabled
                                void close()
                                {
                                if( INVALID_HANDLE_VALUE != this->_handle_file )
                                {
                                 
                                if( FALSE == ::CloseHandle( this->_handle_file ) )
                                {
                                auto error_code = ::GetLastError();
                                throw std::system_error( error_code, std::system_category(), "CloseHandle in file::close()" );
                                }
                                 
                                this->_handle_file = INVALID_HANDLE_VALUE;
                                }
                                }


                              А пользователь класса, явно вызывает метод close() для закрытия файла. В таком случае, деструктор лишь проверяет, что хэндл закрыт и завершается.
                              Если пользователь забыл или не смог закрыть файл, то тогда деструктор автоматически закрывает открытый файл.

                              Эм-эм-эм... Вот вообще, ни разу, не помню, чтоб CloseHandle() возвращала ошибку, если ей передавали правильный хэндл.
                              Но, вероятность такая есть, так что пусть будет исключение, на тот самый, невероятный случай.

                              Хотя... Вот есть иная, тоже интересная задачка. Это классы scope_exit, scope_success, scope_failure. Они в конструкторе принимают лямду. А в деструкторе эту лямду вызывают. И эти лямды, могут ведь тоже бросить исключения!
                                Цитата Eric-S @

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

                                Ну, у меня основная идея в том, что надо каждый вызов заворчивать в подобную конструкцию. Если у тебя не отработала одна функция в деструкторе, почему не должны отработать другие?

                                Добавлено
                                У меня этот макрос выглядит примерно так
                                ExpandedWrap disabled
                                  TS_NOEXCEPT(m_cnn.RollbackTrans());


                                Добавлено
                                Цитата Eric-S @

                                Хотя... Вот есть иная, тоже интересная задачка. Это классы scope_exit, scope_success, scope_failure. Они в конструкторе принимают лямду. А в деструкторе эту лямду вызывают. И эти лямды, могут ведь тоже бросить исключения!

                                Я такую штуку довольно активно использую

                                Добавлено
                                Что–то, похоже, одновременно пишем
                                Сообщение отредактировано: Олег М -
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (6) [1] 2 3 ...  5 6 все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0810 ]   [ 17 queries used ]   [ Generated: 29.03.24, 05:30 GMT ]