На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> как скопировать модификатор 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. Они в конструкторе принимают лямду. А в деструкторе эту лямду вызывают. И эти лямды, могут ведь тоже бросить исключения!

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

                                Добавлено
                                Что–то, похоже, одновременно пишем
                                Сообщение отредактировано: Олег М -
                                  Цитата Олег М @
                                  Ну, у меня основная идея в том, что надо каждый вызов заворчивать в подобную конструкцию. Если у тебя не отработала одна функция в деструкторе, почему не должны отработать другие?

                                  Идея понятная. Подход правомочный.

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

                                  Ну, например, в сложном деструкторе выполняются сложные действия.
                                  1. сбросить кэш в файл.
                                  2. закрыть файл.
                                  3. удалить резервную копию файла.
                                  Если сбой произошёл на первом шаге, то остальные шаги теряют смысл и даже вредят.

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

                                  Напомню, что это моё, сугубо личное мнение. Вы можете делать так, как хотите.

                                  Добавлено
                                  Цитата Олег М @
                                  Я такую штуку довольно активно использую

                                  Полезная примочка.

                                  Добавлено
                                  Цитата Олег М @
                                  Что–то, похоже, одновременно пишем

                                  Я тут набегами. Отвлекусь от кода или бытовухи, проверю почту, а там уведомление...

                                  Вот сейчас, видимо, пойду за стол, дамы хотят праздник.
                                    Цитата Eric-S @
                                    Ну, например, в сложном деструкторе выполняются сложные действия.
                                    1. сбросить кэш в файл.
                                    2. закрыть файл.
                                    3. удалить резервную копию файла.
                                    Если сбой произошёл на первом шаге, то остальные шаги теряют смысл и даже вредят.


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

                                    Добавлено
                                    Цитата Eric-S @
                                    А если уж совсем правильно, то надо примерно так:

                                    void close()
                                    {


                                    Совсем правильно, по-моему будет void close() noexcept {......
                                    Зачем тебе там exception?

                                    Добавлено
                                    Цитата Eric-S @
                                    on_exception( std::current_exception() );

                                    Кстати, а как ты обрабатываешь результат std::current_exception()? С ним вроде особо нельзя ничего сделать, кроме rethrow
                                    Сообщение отредактировано: Олег М -
                                      Цитата Олег М @
                                      Кстати, а как ты обрабатываешь результат std::current_exception()? С ним вроде особо нельзя ничего сделать, кроме rethrow

                                      Основное преимущество типа std::exception_ptr в том, что он может указывать на любое исключение. Даже если это исключение неожиданного типа.

                                      В таком случае, прототип функции моего обработчика выглядит так:
                                      ExpandedWrap disabled
                                        void general_exception_handler( std::exception_ptr p_except );


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

                                      Но за любые плюшки приходится платить, в том числе и за эту универсальность. Приходится востанавливать исключение и обрабатывать его штатно.
                                      ExpandedWrap disabled
                                        /**
                                        @brief ссылка на поток стандартного вывода ошибок.
                                        */
                                        #if defined(_UNICODE) // _UNICODE
                                        basic_ostream< wchar_t >& tcerr = wcerr;
                                        #else // _UNICODE
                                        basic_ostream< char >& tcerr = cerr;
                                        #endif // _UNICODE
                                         
                                         
                                        /**
                                        @brief выводит описание исключения.
                                        @param[in] except ссылка на объект исключения.
                                        */
                                        void output_exception( const exception& except )
                                          {
                                          tcerr << _T( "catched " ) << typeid( except ).name() << endl << except.what() << endl;
                                          } // end function
                                         
                                         
                                        /**
                                        @brief выводит описание исключения.
                                        */
                                        void output_exception()
                                          {
                                          tcerr << _T( "catched unexpected exception" ) << endl;
                                          } // end function
                                         
                                         
                                        /**
                                        @brief главный обработчик исключений.
                                        @param[in] p_exception указатель на исключение.
                                        */
                                        void general_exception_handler( const exception_ptr p_exception )
                                          {
                                          try
                                            {
                                         
                                            /* повторить исключение. */
                                            if( nullptr != p_exception )
                                              {
                                              rethrow_exception( p_exception );
                                              } // end if
                                         
                                            } // end try
                                          catch( const exception& except )
                                            {
                                            output_exception( except );
                                            } // end catch
                                          catch( ... )
                                            {
                                            output_exception();
                                            } // end catch
                                          } // end function


                                      Почти так у меня сделано в консольных прогах. Срезал фигню об system_error, structured_exception и stack_trace.

                                      Цитата Олег М @
                                      Совсем правильно, по-моему будет void close() noexcept {......
                                      Зачем тебе там exception?


                                      Понятия не имею. Но в справочнике для функции CloseHandle() прописано, что она может вернуть код ошибки.
                                      И я, просто обязан, эту ошибку обработать!

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

                                      Правда вот тут, наткнулся на новую идею. Пока ещё не занялся, но серьёзно раздумываю сделать свой std::expected. С ним будет проще и дешевле обрабатывать ошибки, чем с исключениями.

                                      А сейчас я колупаю noexcept...

                                      Читал тырнет и понял, что само проверяемое выражение надо оборачивать в дополнительный noexcept.
                                      ExpandedWrap disabled
                                        template< typename ValueType >
                                        class someclass
                                        {
                                        public:
                                         
                                        someclass() noexcept( noexcept( _construct() ) ),
                                        _is_good( false )
                                        {
                                        _construct();
                                        }
                                         
                                        bool is_good() const noexcept
                                        {
                                        return _is_good;
                                        }
                                         
                                        private:
                                         
                                        void _construct() noexcept( is_nothrow_default_constructible< ValueType >::value )
                                        {
                                        new( &_value ) ValueType();
                                        _is_good = true;
                                        }
                                         
                                         
                                        char _value[ sizeof( ValueType ) ];
                                         
                                        /* флаг что объект построен. */
                                        bool _is_good;
                                         
                                        };


                                      Ну... Э-э-э-, как-то так.

                                      А теперь хардкорище
                                      ExpandedWrap disabled
                                        someclass() noexcept( noexcept( bla_bla_bla ) )

                                      И оно же компилируется!

                                      Вообщем, такая заморочка, для одной функции написал проверочку. Но оно тоже компилируется. А я же засомневался, коректна ли та проверка или компиль увидел там bla_bla_bla?

                                      ExpandedWrap disabled
                                        void set_value( const_reference value ) noexcept( noexcept( _construct( value ) ) && noexcept( _assign( value ) ) )
                                        {
                                        if( is_good() )
                                        {
                                        _assign( value );
                                        }
                                        else
                                        {
                                        _construct( value );
                                        }
                                        }


                                      На примерно такой код компилятор не ругался.
                                      Сообщение отредактировано: Eric-S -
                                        Цитата Eric-S @
                                        Понятия не имею. Но в справочнике для функции CloseHandle() прописано, что она может вернуть код ошибки.
                                        И я, просто обязан, эту ошибку обработать!

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


                                        Может быть. Я в таких случаях - CloseHandle, close и т.п. - особенно в деструкторах, просто забиваю на эти коды и всё. Смысл напрягаться, если по-любому не можешь ничего сделать и никак среагировать? Обрабатываю, только ели мне это действительно нужно. Но таких случаев не припомню.


                                        Цитата Eric-S @
                                        Правда вот тут, наткнулся на новую идею. Пока ещё не занялся, но серьёзно раздумываю сделать свой std::exception. С ним будет проще и дешевле обрабатывать ошибки, чем с исключениями.


                                        Что за идея?

                                        Добавлено
                                        Цитата Eric-S @
                                        А теперь хардкорище

                                        someclass() noexcept( noexcept( bla_bla_bla ) )

                                        И оно же компилируется!


                                        Почему бы нет? noexcept это и оператор и модификатор

                                        Добавлено
                                        Цитата Eric-S @
                                        if( is_good() )


                                        Что такое is_good?
                                          Цитата Олег М @
                                          Что за идея?

                                          Ой... Опять поспешил. Конечно же std::expected.

                                          Это шаблоный клас, который содержит в себе union. Он может хранить своё состояние, а так же либо код ошибки, либо возвращаемое значение.

                                          То есть функция возвращает объект типа std::expected.
                                          Если функция завершилась нормально, то в объекте лежит нормальное значение.
                                          Если функция завершилась с ошибкой, то в объекте лежит код ошибки.

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

                                          Далее, есть мысль, бросать ещё одно исключение из деструктора expected.
                                          Это в том случае, если вызвавший функцию, по какой-то причине вообще проигнорировал возвращёное значение.
                                          То есть кто-то функцию вызвал, значение запросил, но проигнорировал его.

                                          Добавлено
                                          Цитата Олег М @
                                          Почему бы нет? noexcept это и оператор и модификатор

                                          Понятно, что оператор. Но там же написано заведомо недопустимое выражение.
                                          Соответственно, я теперь сомневаюсь, а допустимо ли моё выражение? Или же компиль молче сжевал недопустимое?

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

                                          А... Ну, в данном случае is_good() это constexpr метод noexcept(true) который возвращает true если уже был вызван метод _construct иначе false.
                                          Смысл в том, что он подтверждает, что в поле _value находится действительно объект, а не сырые неинициализированные данные.
                                            Цитата Eric-S @
                                            Тот кто вызывает функцию, должен проверить код ошибки, если всё нормально, то он может получить значение.
                                            Если же пытается получить значение, а в объекте код ошибки, то будет брошено исключение.
                                            Ну... Стратегия ленивого, отложенного исключения.
                                            Оно будет брошено только тогда, когда без него уже не обойтись.


                                            Типа, возвращение к старому доброму Си? Не, по мне так лучше исключения отлавливать.


                                            Цитата Eric-S @
                                            Далее, есть мысль, бросать ещё одно исключение из деструктора expected.

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

                                            Добавлено
                                            Цитата Олег М @
                                            А... Ну, в данном случае is_good() это constexpr метод noexcept(true) который возвращает true если уже был вызван метод _construct иначе false.
                                            Смысл в том, что он подтверждает, что в поле _value находится действительно объект, а не сырые неинициализированные данные.


                                            Только там у тебя будут всегда компилироваться обе ветки. Это надо, наверное, через std::enable_if делать. Либо через requires
                                              Цитата Олег М @
                                              Только там у тебя будут всегда компилироваться обе ветки. Это надо, наверное, через std::enable_if делать. Либо через requires

                                              Естественно будут компилироватся обе ветки. Потому что в объекте в разное время могут быть инициализированные или неинициализированные данные. В данном случае метод is_good() будет отрабатывать в run-time.
                                              Но мысль, перенести часть в compile-time кажется интересной. Надо над этим подумать.
                                                Цитата Eric-S @
                                                Естественно будут компилироватся обе ветки. Потому что в объекте в разное время могут быть инициализированные или неинициализированные данные. В данном случае метод is_good() будет отрабатывать в run-time.
                                                Но мысль, перенести часть в compile-time кажется интересной. Надо над этим подумать.

                                                Думаю, там придётся переносить в compile-time. Одна специализация для construct, одна для assign и третья для обоих всесте
                                                  Цитата Олег М @
                                                  Типа, возвращение к старому доброму Си? Не, по мне так лучше исключения отлавливать.

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

                                                  Предложение std::expected в новый стандарт, было отклонено со словами, что в C++ уже есть механизм обработки ошибок.

                                                  Бросать кучу исключений, тоже плохо.
                                                  В стандартных контейнирах, вроде std::vector, есть два варианта доступа к элементам: operator[], который не бросает исключений; и метод at() который исключения бросает.
                                                  В сомнительных случаях, лучше юзать метод at(). А в циклах, для повышения скорости, предпочтителен operator[].
                                                  То есть пользователю нужно дать вариант выбора, либо метод с исключениями, либо метод без исключений, но с проверкой ошибок.
                                                  И std::expected предлагает вариант решения.

                                                  Ну.. Уже написал, что буду ещё думать. Идея интересная, но сомнительная.

                                                  Добавлено
                                                  Цитата Олег М @
                                                  Думаю, там придётся переносить в compile-time. Одна специализация для construct, одна для assign и третья для обоих всесте

                                                  Понятия не имею как такой трюк устроить. Наверное придётся магичить с шаблонами.
                                                    Цитата Eric-S @
                                                    Понятия не имею как такой трюк устроить. Наверное придётся магичить с шаблонами.

                                                    А ты в чём компилируешь? Там концепты поддерживаются - concept, requires? С ними совсем просто
                                                    Сообщение отредактировано: Олег М -
                                                      Цитата Олег М @
                                                      А ты в чём компилируешь? Там концепты поддерживаются - concept, requires? С ними совсем просто

                                                      visual studio 2015. Уже скачал но не установил 2017.

                                                      Что такое концепты примерно слышал, но реальных руками не щупал.

                                                      Что такое requires я не знаю, не сталкивался.
                                                        Цитата Eric-S @
                                                        Что такое концепты примерно слышал, но реальных руками не щупал.

                                                        Это условия для шаблонов. Крутая штука, правда я тоже пока с трудом понимаю, но использую активно, в gcc
                                                        ExpandedWrap disabled
                                                          template <typename T, typename TFunc, typename... TT> requires !std::is_same<std::result_of_t<TFunc(TT...)>, void>::value
                                                          auto CallNoVoid(T &&_void, TFunc &&func, TT&&... args)
                                                          {
                                                              return std::invoke(std::forward<TFunc>(func), std::forward<TT>(args)...);
                                                          }
                                                           
                                                          template <typename T, typename TFunc, typename... TT> requires std::is_same<std::result_of_t<TFunc(TT...)>, void>::value
                                                          auto CallNoVoid(T &&_void, TFunc &&func, TT&&... args)
                                                          {
                                                              std::invoke(std::forward<TFunc>(func), std::forward<TT>(args)...);
                                                              return std::forward<T>(_void);
                                                          }


                                                        Добавлено
                                                        ExpandedWrap disabled
                                                          template <typename T> concept bool IsSharedMutex = requires(T a) {{a.lock_shared()}; {a.unlock_shared()};};
                                                           
                                                          template <typename T> requires !IsSharedMutex<T> && !std::is_same<T, std::atomic_flag>::value
                                                          using lock_guard = std::lock_guard<T>;
                                                           
                                                          template <IsSharedMutex T>
                                                          using lock_guard2 = std::lock_guard<T>;


                                                        Добавлено
                                                        Во втором случае IsSharedMutex == true, если у объекта типа T есть методы lock_shared и unlock_shared
                                                        lock_guard существует для всех, кроме IsSharedMutex
                                                        lock_guard2 - только для IsSharedMutex

                                                        Добавлено
                                                        ExpandedWrap disabled
                                                          template <typename T> concept bool IsFormatable = requires(const T a, std::ostream &out) {a.FormatVal(out);};
                                                           
                                                          template <typename T>
                                                          void Format(std::ostream &out, T &&val)
                                                          {
                                                              out << std::forward<T>(val);
                                                          }
                                                           
                                                          template <IsFormatable T>
                                                          void Format(std::ostream &out, T &&val)
                                                          {
                                                              val.FormatVal(out);
                                                          }
                                                          Цитата Олег М @
                                                          Это условия для шаблонов. Крутая штука, правда я тоже пока с трудом понимаю, но использую активно

                                                          Эм-эм-эм... Тогда мы говорим о разных концептах.
                                                          Где-то, в какой-то статье подсмотрел принцип идеи. Вроде бы о языке D.
                                                          Концепт, в моём понимании, это специальный тип, который создаёт интерфейс для объектов со статическим полиморфизмом.

                                                          То есть например, некая статическая компилируемая функция, просит в качестве параметра некий концепт коллекции.
                                                          И этой функции, можно передать любую коллекцию, которая соответствует концепту коллекции std::vector, std::list или ещё чего.

                                                          Вроде бы, шёл разговор, о принятии концептов в C++ 17. Но предложение было слишком большим и сложным. Его отправили на доработку. Хотели принять облегчённый вариант, но кажись с ним тоже облом.
                                                            Цитата Eric-S @
                                                            Вроде бы, шёл разговор, о принятии концептов в C++ 17. Но предложение было слишком большим и сложным. Его отправили на доработку. Хотели принять облегчённый вариант, но кажись с ним тоже облом.

                                                            Я ж прислал примеры, рабочие

                                                            Добавлено
                                                            Цитата Eric-S @
                                                            Концепт, в моём понимании, это специальный тип, который создаёт интерфейс для объектов со статическим полиморфизмом.

                                                            А это не template?

                                                            Добавлено
                                                            Компилирую под gcc 6.2.0

                                                            Добавлено
                                                            Цитата Eric-S @
                                                            Концепт, в моём понимании, это специальный тип, который создаёт интерфейс для объектов со статическим полиморфизмом.

                                                            Кстати да, тут ты прав. Но, разве IsSharedMutex не определяет именно такой интерфейс, или IsFormatable?
                                                            Сообщение отредактировано: Олег М -
                                                              Цитата Олег М @
                                                              Я ж прислал примеры, рабочие

                                                              Если в каких-то компиляторах сделано, то это не значит, что принято в стандарте и наоборот.
                                                                Цитата Eric-S @
                                                                Если в каких-то компиляторах сделано, то это не значит, что принято в стандарте и наоборот.

                                                                Скорее наоборот. Microsoft всегда довольно сильно отставал от стандарта.
                                                                Ну да ладно. В твоём случае, по-моему, надо смотреть в сторону std::enable_if и std::condition. Вроде constexpr-функции можно передавать в качестве аргумента шаблона
                                                                Сообщение отредактировано: Олег М -
                                                                  Цитата Олег М @
                                                                  Цитата Eric-S @
                                                                  Концепт, в моём понимании, это специальный тип, который создаёт интерфейс для объектов со статическим полиморфизмом.

                                                                  А это не template?

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

                                                                  Динамический (виртуальный) полиморфизм, это когда есть интерфейс (класс с чисто виртуальными функциями). А другие классы реализуют этот интерфейс, переопределяя виртуальные функции. Но доступ к таким членам происходит динамически через таблицу виртуальных функций.

                                                                  Статический полиморфизм, это когда некий интерфейс подразумевается, но нигде не прописан. Просто у разных класов есть функции с одинаковыми названиями, одинаковыми параметрами и одинаковыми возвращаемыми значениями. Шаблонные функции могут принимать объекты разных классов и совершать с ними одинаковые действия. Например "back_inserter" или "front_inserter" могут принимать любые колекции с одинаковым статическим интерфейсом. Доступ к членам объектов со статическим полиморфизмом происходит без дополнительных расходов на вызов.

                                                                  Вот это, всё, как бы хорошо. Но одно противопостовляется другому.

                                                                  Функция которая юзает объект с динамическим полиморфизмом, может быть скомпилирована и помещена в исполняемый код библиотеки. Такая функция принимает только ссылку или указатель на объект. Но если тип объекта не унаследовал и нереализовал специальный виртуальный интерфейс, то обломс!

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

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

                                                                  Кстати, функции std::begin и std::end примерно так же обёртывают объект произвольного типа и возвращают итераторы. Это конечно не концепт, но что-то в этом есть.

                                                                  А вот класс string_view ещё ближе к реализации одного из концептов. Обёртывает std::basic_string или char* и предоставляет единый интерфейс к строке.

                                                                  Добавлено
                                                                  Цитата Олег М @
                                                                  Microsoft всегда довольно сильно отставал от стандарта.

                                                                  Не всегда. Что-то они реализовывали раньше и даже намного раньше выхода стандарта. А где-то совсем опережают, о чём стандарт даже и не думал. Другие компиляторы делают так же. Например модули запилили в msvc и clang, а в стандарте их ещё обсуждают. А у gcc, вроде бы до сих пор нет предкомпилированных хидеров.

                                                                  Добавлено
                                                                  Цитата Олег М @
                                                                  В твоём случае, по-моему, надо смотреть в сторону std::enable_if и std::condition. Вроде constexpr-функции можно передавать в качестве аргумента шаблона

                                                                  Я ещё долблюсь с этим noexcept.
                                                                  Заметил тут забавную штуку.
                                                                  Если просто написать выражение
                                                                  ExpandedWrap disabled
                                                                    template< typename T >
                                                                    class someclass
                                                                    {
                                                                    public:
                                                                     
                                                                    someclass() noexcept( bla_bla_bla )
                                                                     
                                                                    };

                                                                  то оно компилируется.
                                                                  Но если запросить модификатор noexcept, то тогда это выражение проверяется.
                                                                  ExpandedWrap disabled
                                                                    cout << "someclass noexcept = " << noexcept( someclass() ) << endl;

                                                                  И в случае если выражение кривое, то падает с ошибкой компиляции.

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

                                                                  Добавлено
                                                                  Цитата Олег М @
                                                                  Но, разве IsSharedMutex не определяет именно такой интерфейс, или IsFormatable?

                                                                  Не имею понятия. Я не гуру. А программированием лишь балуюсь, время от времени. Так... Только поверхам нахватался всяких простых вещей. Ну, э-э-э, как вывести текст в консоль или как прочитать ввод и ещё немного сверх этого. А современную официальную спецификацию C++ на английском, даже не читал.

                                                                  Добавлено
                                                                  Цитата Олег М @
                                                                  надо смотреть в сторону std::enable_if и std::condition. Вроде constexpr-функции можно передавать в качестве аргумента шаблона

                                                                  Всё же задумался, как же там реализовать.
                                                                  Ну ладно, для compile-time понятно, как выбрать ветку.

                                                                  ExpandedWrap disabled
                                                                    void _if_set_value( const_reference value, false_type )
                                                                    {
                                                                    _construct( value );
                                                                    }
                                                                     
                                                                    void _if_set_value( const_reference value, true_type )
                                                                    {
                                                                    _assign( value );
                                                                    }
                                                                     
                                                                    void _if_set_value( value_reference value )
                                                                    {
                                                                    typedef typename condition< is_good(), true_type, false_type >::type variant_type;
                                                                    _if_set_value( value, variant_type() );
                                                                    }


                                                                  А как выбрать ветку для run-time?

                                                                  Ой, да ну. Пусть всё идёт в run-time, там же одно условие, которое проверяет динамической значение константы.
                                                                    Цитата Олег М @
                                                                    Опять же. По-моему, очень плохая мысль бросать исключение из деструктора. Недоудалённые объекты и всё такое.

                                                                    Угу. Не все гениальные предложения Александреску одинаково полезны...
                                                                      Цитата Eric-S @
                                                                      Не имею понятия. Я не гуру. А программированием лишь балуюсь, время от времени. Так...

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

                                                                      Добавлено
                                                                      Цитата Eric-S @
                                                                      А у gcc, вроде бы до сих пор нет предкомпилированных хидеров.

                                                                      Ну и хрен сними. Там и заголовков майкрософтовских нет. Зато они 17 стандарт поддерживают, концепты и все дела.

                                                                      Добавлено
                                                                      Цитата Eric-S @
                                                                      И в случае если выражение кривое, то падает с ошибкой компиляции.

                                                                      Потому что ты инстанциирвоал функцию. Если ты в шаблонном классе сделал функцию, но не вызвал ее, компилятор забивает на ошибки

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

                                                                      Ой, да ну. Пусть всё идёт в run-time, там же одно условие, которое проверяет динамической значение константы

                                                                      Сдался?
                                                                      Не стоит, там есть решение. Хотя, тоже не знаю какое
                                                                      Сообщение отредактировано: Олег М -
                                                                        Цитата Олег М @
                                                                        Потому что ты инстнциироал функцию. Если ты в шаблонном кассе сделал функцию, но не вызвал ее, компилятор забивает на ошибки

                                                                        Фигня какая-то. Я специально, для отлова ошибок, инстанцировал явно весь шаблон класса, со всеми его предками.

                                                                        Сейчас сижу и набиваю проверки noexcept, через static_assert.

                                                                        С одним шаблонным классом вроде прокатило нормально, а с главным классом всё облом.
                                                                        Он мне упорно говорит, что у меня конструктор noexcept( false). Если я напишу явно noexcept( true ) тогда да, всё норм. А когда наследую noexcept от конструктора базового класса, то ой, опять false.

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

                                                                        Из того, что ты написал, я не очень понял, кто там от кого. Ибо есть незнакомые слова, о смысле которых я могу лишь догадываться.
                                                                        Да, вроде статический полиморфизм, судя по вызовам в функции. Но он же, этот статический полиморфизм был и раньше.
                                                                          Цитата Eric-S @

                                                                          Фигня какая-то. Я специально, для отлова ошибок, инстанцировал явно весь шаблон класса, со всеми его предками.

                                                                          Очевидно, не весь.
                                                                            Цитата Олег М @
                                                                            Сдался?
                                                                            Не стоит, там есть решение. Хотя, тоже не знаю какое

                                                                            Даже не брался по серьёзному. Так, Только немного задумался.
                                                                            Сейчас грызу noexcept, по сабжу данной темы. Чего-то опять не сходится ожидаемое с получаемым.
                                                                              Цитата Eric-S @
                                                                              Да, вроде статический полиморфизм, судя по вызовам в функции. Но он же, этот статический полиморфизм был и раньше

                                                                              Раньше ты в шаблоне не мог указать какие функции должны присутствовать у класса.

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

                                                                              Сейчас сижу и набиваю проверки noexcept, через static_assert

                                                                              Кстати, это хорошая идея.
                                                                                Цитата Олег М @
                                                                                Очевидно, не весь.

                                                                                Ну вот у меня четыре шаблонных класса
                                                                                ExpandedWrap disabled
                                                                                  template< type T > union a{ ... };
                                                                                   
                                                                                  template< type T > class B abstract { typedef T value_type; ... };
                                                                                   
                                                                                  template< type T, bool F > class C abstract;
                                                                                   
                                                                                  template< type T > class C< T, false > abstract: public B< T > { ... };
                                                                                   
                                                                                  template< type T > class C< T, true > abstract: public B< T > { ... };
                                                                                   
                                                                                  template< typename T, bool F = false > class D final: public C< T, F > { typedef C< T, F > base_type; typedef typename base_type::value_type value_type; ... };


                                                                                Я их инстанцирую.

                                                                                ExpandedWrap disabled
                                                                                  template union A< stub >;
                                                                                  template class B< stub >;
                                                                                  template class B< stub >;
                                                                                  template class C< stub, false >;
                                                                                  template class C< stub, true >;
                                                                                  template class D< stub, false >;
                                                                                  template class D< stub, true >;


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

                                                                                Единственное, грешу, на класс C, для которого у меня две специализации.

                                                                                Там даже была накладка с наследованием типа. Пришлось явно тащить typedef value_type.

                                                                                Возможно он точно так же не находит конструктор класса C.
                                                                                  Цитата Eric-S @

                                                                                  Или, шаблонный класс, надо как-то иначе инстанцировать?

                                                                                  Я вообще не вижу, чтоб ты их инстанциировал.
                                                                                  Надо как–то переменные от них обьявить

                                                                                  Добавлено
                                                                                  А чтоб методы – надо их вызвать
                                                                                  Сообщение отредактировано: Олег М -
                                                                                    Цитата Олег М @
                                                                                    Я вообще не вижу, чтоб ты их инстанциировал.

                                                                                    Дык, а это:
                                                                                    ExpandedWrap disabled
                                                                                      template class D< stub, true >;


                                                                                    А в хидере написано:
                                                                                    ExpandedWrap disabled
                                                                                      extern template class D< stub, true >;


                                                                                    Чтоб компилятор не инстанцировал этот шаблон в других объектных файлах, а искал уже готовый код.

                                                                                    Добавлено
                                                                                    Цитата Олег М @
                                                                                    Надо как–то переменные от них обьявить
                                                                                    А чтоб методы – надо их вызвать

                                                                                    Это в простом случае. Но тогда инстанциируется только то, что вызывается.
                                                                                    И да, оно у меня в тестах, почти всё вызывается. Примерно покрытие кода тестами на 80%. Руки не дошли протестировать операторы сравнения и парочку методов.
                                                                                      Цитата Eric-S @
                                                                                      то оно компилируется.
                                                                                      Но если запросить модификатор noexcept, то тогда это выражение проверяется.

                                                                                      cout << "someclass noexcept = " << noexcept( someclass() ) << endl;

                                                                                      И в случае если выражение кривое, то падает с ошибкой компиляции


                                                                                      А попробуй создать здесь просто экземпляр класса. Что выяснить, что проблема не в noexcept
                                                                                        Цитата Олег М @
                                                                                        А попробуй создать здесь просто экземпляр класса. Что выяснить, что проблема не в noexcept

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

                                                                                        Но я всё же понял в чём был косяк.
                                                                                        1. я проверял конструктор через std::is_nothrow_default_constructible.
                                                                                        2. конструктор был protected.
                                                                                        3. класс был abstract.

                                                                                        Ну.. Проверял ещё кучу условий, всякие там вложенные объекты, пустые специализации шаблонов и прочее и прочее.

                                                                                        Я попробовал убрать protected, но нет, не работает, вернул.
                                                                                        Я попробовал убрать abstract, но нет, тоже не работает, вернул.
                                                                                        Вот когда я убрал вместе сразу protected и abstract, то проверка прошла успешно.

                                                                                        Блин!!! Вот я тупой! это же is_nothrow_default_constructible шаблонный клас, и он тупо не мог получить доступа к защищённому члену!
                                                                                        Сообщение отредактировано: Eric-S -
                                                                                          Цитата Eric-S @
                                                                                          Вот когда я убрал вместе сразу protected и abstract, то проверка прошла успешно.

                                                                                          Блин!!! Вот я тупой! это же is_nothrow_default_constructible шаблонный клас, и он тупо не мог получить доступа к защищённому члену!

                                                                                          Тебе не кажется, что что–то ты делаешь неправильно? Не должен модификатор nothrow зависеть от слова protected

                                                                                          Добавлено
                                                                                          Кстати, а разве можно создать экземпляр класса abstract?
                                                                                            Цитата Олег М @
                                                                                            Кстати, а разве можно создать экземпляр класса abstract?

                                                                                            Ну надо же как-то скопировать модификатор из protected метода abstract класса, в public метод final класса?
                                                                                              Цитата Олег М @
                                                                                              Тебе не кажется, что что–то ты делаешь неправильно? Не должен модификатор nothrow зависеть от слова protected

                                                                                              Делаю правильно. А вот тестировать захотел слишком много.

                                                                                              Банально, попытался унаследовать noexcept, с помощью постороннего класса. Сейчас прописываю всё руками, через noexcept( noexcept( ... ) ) и оно вроде даже наследуется, если судить по результатам тестов.
                                                                                                Цитата Eric-S @
                                                                                                Кстати, а разве можно создать экземпляр класса abstract?

                                                                                                Ну надо же как-то скопировать модификатор из protected метода abstract класса, в public метод final класса?


                                                                                                Не лучше ли его там явно указать? Или сделать using base_class::method;, в public:?
                                                                                                  Цитата Олег М @
                                                                                                  Не лучше ли его там явно указать? Или сделать using base_class::method;, в public:?

                                                                                                  Ой, нет. дело совсем не в том.

                                                                                                  Вот у меня конструктор
                                                                                                  ExpandedWrap disabled
                                                                                                    D() noexcept( noexcept( base_type() ) ):
                                                                                                    base_type()
                                                                                                    {
                                                                                                    ...
                                                                                                    }


                                                                                                  Так и получается, что внутри объекта класса D, создаётся объект класса base_type.

                                                                                                  Я по началу писал std::is_nothrow_default_constructible< base_type >::value и он всегда возвращал мне false.


                                                                                                  Когда я написал noexcept( base_type() ), то компиль сказал, что нельзя создать объект абстрактного класса.

                                                                                                  В итоге плюнул на носледование noexcept и написал проще:
                                                                                                  ExpandedWrap disabled
                                                                                                    D() noexcept( false )
                                                                                                    {
                                                                                                    ...
                                                                                                    }


                                                                                                  Если есть сомнение, что где-то, кто-то, когда-то бросит исключение, то он наверняка его бросит.
                                                                                                    Вот такой код у меня вроде нормально отработал - выдал warning, там где положено
                                                                                                    ExpandedWrap disabled
                                                                                                      struct CTestBase
                                                                                                      {
                                                                                                          CTestBase() noexcept
                                                                                                          {
                                                                                                          }
                                                                                                       
                                                                                                          CTestBase(int)
                                                                                                          {
                                                                                                          }
                                                                                                       
                                                                                                      };
                                                                                                       
                                                                                                      struct CTest
                                                                                                      : public CTestBase
                                                                                                      {
                                                                                                          CTest() noexcept(!std::is_nothrow_constructible<CTestBase>::value)
                                                                                                          {
                                                                                                              throw 1;
                                                                                                          }
                                                                                                       
                                                                                                          CTest(int) noexcept(!std::is_nothrow_constructible<CTestBase, int>::value)
                                                                                                              : CTestBase(n)
                                                                                                          {
                                                                                                              throw 1; //warning: throw will always call terminate() [-Wterminate]
                                                                                                          }
                                                                                                      };


                                                                                                    Добавлено
                                                                                                    Под gcc
                                                                                                    Сообщение отредактировано: Олег М -
                                                                                                      Цитата Олег М @
                                                                                                      std::is_nothrow_constructible<CTestBase>::value

                                                                                                      Он будет корректным, только пока CTestBase останется открытым классом.
                                                                                                      А если его конструктор сделать protected и добавить ключевое слово abstract в объявлении, то всё сломается.

                                                                                                      Так и должно быть, по логике наследования и защиты. Но в таком случае не получается скопировать модификатор noexcept у конструктора.
                                                                                                        Цитата Eric-S @
                                                                                                        А если его конструктор сделать protected и добавить ключевое слово abstract в объявлении, то всё сломается.

                                                                                                        У меня с ним почему-то не компилится, я пытался

                                                                                                        Добавлено
                                                                                                        Но на самом деле, я думаю, что это не слишком хорошая практика - так объявлять noexcept для методов. Ухудшает читабельность кода.
                                                                                                        Лучше, наверное, сделать так

                                                                                                        ExpandedWrap disabled
                                                                                                              CTest(int n) noexcept
                                                                                                              : CTestBase(n)
                                                                                                              {
                                                                                                                  static_assert(std::is_nothrow_constructible<CTestBase, int>::value);
                                                                                                              }
                                                                                                          Цитата Олег М @
                                                                                                          Вот такой код у меня вроде нормально отработал - выдал warning, там где положено

                                                                                                          Этот приём называется подгонкой условий задачи под правильный ответ.

                                                                                                          Усилия оценил. Да, всё верно, так действительно должно работать.

                                                                                                          Но крайне желательно, чтоб CTestBase был именно закрытым классом. Чтоб пользователь не мог создать его объекта.

                                                                                                          Добавлено
                                                                                                          Цитата Олег М @
                                                                                                          У меня с ним почему-то не компилится, я пытался

                                                                                                          Ха-эм... Наверное gcc не поддерживает.
                                                                                                            Соответственно
                                                                                                            ExpandedWrap disabled
                                                                                                                  void CTest::func() noexcept
                                                                                                                  {
                                                                                                                      static_assert(noexcept(CTestBase::func()));
                                                                                                                      CTestBase::func();
                                                                                                                  }
                                                                                                              Цитата Олег М @
                                                                                                              Но на самом деле, я думаю, что это не слишком хорошая практика - так объявлять noexcept для методов. Ухудшает читабельность кода.


                                                                                                              Впринципе да, ухудшает.

                                                                                                              Но у меня обёртка для неизвестного объекта value_type, с кучей заранее неизвестных факторов.

                                                                                                              Вот и хочется прогнуться под объект. Если у того объекта конструкторы, деструкторы и прочие сервисные члены noexcept( true ), так это замечательно.
                                                                                                              Но вдруг у него что-то объявлено, как noexcept( false ), а моя обёртка это исключение перехватит и уронит прогу?

                                                                                                              Ради читабельности, мне придётся всё объявлять noexcept( false ). Только в этом случае, вложенный объект будет корректно обработан. Пусть и с дополнительными накладными расходами.

                                                                                                              Правильнее будет аккуратно скопировать модификатор noexcept из чужого объекта и сделать у себя такой же модификатор.
                                                                                                              Да, читабельность из-за этого всего сломается. Это уж наверняка. Но зато поднимется юзабельность.

                                                                                                              И ещё, такой момент. Некоторые члены базового класса зависят от членов дочернего класса. Точнее от одной из нескольких специализаций дочернего класса. А там, модификаторы noexcept вообще прибиты гвоздями. В некоторых случаях, я скопировал из value_type. А в другой специализации использовал хак и заведомо поставил noexcept( true ). Так что модификаторы уже не зависят от самого объекта.
                                                                                                              Сообщение отредактировано: Eric-S -
                                                                                                                Цитата Eric-S @
                                                                                                                мне придётся всё объявлять noexcept( false )

                                                                                                                Это т.е. не объявлять модификатор noexcept вообще?
                                                                                                                  Цитата Олег М @
                                                                                                                  Это т.е. не объявлять модификатор noexcept вообще?

                                                                                                                  Э, нет! Не знаю как в gcc. А msvc если модификатор noexcept не проставлен, то проставляет их на своё усмотрение. Так что именно, надо проставлять руками, везде, явно noexcept( false ). В таком случае компилятор поймёт и не будет умничать.
                                                                                                                    Цитата Eric-S @
                                                                                                                    А msvc если модификатор noexcept не проставлен, то проставляет их на своё усмотрение.

                                                                                                                    Это где написано? Что-то очень сомневаюсь, чтоб компилятор мог привести к вызову terminate.
                                                                                                                      Цитата Олег М @
                                                                                                                      Это где написано? Что-то очень сомневаюсь, чтоб компилятор мог привести к вызову terminate.

                                                                                                                      https://msdn.microsoft.com/ru-ru/library/dn818588.aspx
                                                                                                                        Кстати, в gcc можно ещё вот такую весёлую штуку сделать
                                                                                                                        ExpandedWrap disabled
                                                                                                                          template <typename T = CTestBase>
                                                                                                                          struct CTest
                                                                                                                          : public T
                                                                                                                          {
                                                                                                                              
                                                                                                                              void func() noexcept requires !noexcept(this->T::func())
                                                                                                                              {
                                                                                                                                  try
                                                                                                                                  {
                                                                                                                                      T::func();
                                                                                                                                  }
                                                                                                                                  catch(...)
                                                                                                                                  {
                                                                                                                                  }
                                                                                                                              }
                                                                                                                           
                                                                                                                              void func() noexcept requires noexcept(this->T::func())
                                                                                                                              {
                                                                                                                                  T::func();
                                                                                                                              }
                                                                                                                           
                                                                                                                          };


                                                                                                                        С шаблонами пока не смог придумать как
                                                                                                                        Сообщение отредактировано: Олег М -
                                                                                                                          Цитата Олег М @
                                                                                                                          Кстати, в gcc можно ещё вот такую весёлую штуку сделать

                                                                                                                          А что в результате она даст?
                                                                                                                            Если в базовом классе метод func() вызывает исключение, то она обернёт его в try-catch.
                                                                                                                            Либо, как вариант, функция в наследнике тоже будет без noexcept
                                                                                                                              Цитата Олег М @
                                                                                                                              С шаблонами пока не смог придумать как

                                                                                                                              А. Теперь понятно. Можно и с шаблонами. Тут ничего сложного. Вместо void проставить enable_if< noexcept( expr), void >::type.
                                                                                                                                Цитата Eric-S @
                                                                                                                                А. Теперь понятно. Можно и с шаблонами. Тут ничего сложного. Вместо void проставить enable_if< noexcept( expr), void >::type.

                                                                                                                                Я так и сделал. Не получается
                                                                                                                                  Цитата Олег М @
                                                                                                                                  Я так и сделал. Не получается

                                                                                                                                  А если перенести объявление типа после списка аргументов?
                                                                                                                                  auto foo() -> return_type
                                                                                                                                    Цитата Eric-S @
                                                                                                                                    А если перенести объявление типа после списка аргументов?
                                                                                                                                    auto foo() -> return_type


                                                                                                                                    Пробовал, говорит cannot be overloaded
                                                                                                                                      Цитата Олег М @
                                                                                                                                      Пробовал, говорит cannot be overloaded

                                                                                                                                      Странно. Ну да фиг с ним. Какая-то задачка безсмысленная. Ну или я смысла в ней не заметил.

                                                                                                                                      Чисто для разминки, можно попробовать enable_if в качестве дополнительного параметра функции.

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

                                                                                                                                        Ну, вообще, для шаблонного класса вполне себе осмысленная. Возможно даже очень. Делает функцию базового класса noexcept.

                                                                                                                                        Добавлено
                                                                                                                                        Цитата Eric-S @
                                                                                                                                        Но я относительно понимаю, только эти два.

                                                                                                                                        Какие?

                                                                                                                                        Добавлено
                                                                                                                                        Цитата Eric-S @
                                                                                                                                        Странно. Ну да фиг с ним. Какая-то задачка безсмысленная. Ну или я смысла в ней не заметил.

                                                                                                                                        Хотя, с другой стороны, тоже нифига не могу придумать как это использовать. Может потом.
                                                                                                                                          Цитата Олег М @
                                                                                                                                          Ну, вообще, для шаблонного класса вполне себе осмысленная. Возможно даже очень. Делает функцию базового класса noexcept.

                                                                                                                                          Хотя, с другой стороны, тоже нифига не могу придумать как это использовать. Может потом.


                                                                                                                                          Вот-вот. Ну, сделает оно функцию noexcept( true ).

                                                                                                                                          И чего тут хорошего? Замолчали исключение. Скрыли проблему. Программу наверняка уронили, без объяснения причин.

                                                                                                                                          Ах да. Я как-то тоже вот так перенаправлял исключения, с помощью try{}catch(...){throw;} Когда ещё не слышал про scope_exit.

                                                                                                                                          Но когда я начал юзать vectored exception handler, для диагностики всех происходящих исключений, даже скрытых, то проклял все места, которые генерировали дополнительные исключения и засирали лог-файл лишним мусором, без внятных объяснений о сути проблемы.

                                                                                                                                          Так что нет. Если кто-то бросает исключение, то пусть бросает его спокойно.
                                                                                                                                          Сообщение отредактировано: Eric-S -
                                                                                                                                            Цитата Eric-S @
                                                                                                                                            И чего тут хорошего? Замолчали исключение. Скрыли проблему. Программу наверняка уронили, без объяснения причин.

                                                                                                                                            Насчёт наверняка уронили, это ты конечно загнул. И не замолчали, а, например, записали в лог и продолжили работу.
                                                                                                                                            В моём случае проблема в том, что когда я перехватываю исключение, то добавляю в лог ещё и file line, где оно было перехвачено. Через макросы это легко получается, а здесь будет проблематично.

                                                                                                                                            Добавлено
                                                                                                                                            Цитата Eric-S @
                                                                                                                                            Когда ещё не слышал про scope_exit.

                                                                                                                                            Что это такое?

                                                                                                                                            Добавлено
                                                                                                                                            Цитата Eric-S @
                                                                                                                                            Так что нет. Если кто-то бросает исключение, то пусть бросает его спокойно.

                                                                                                                                            Бросать его никто не мешает. Проблема в том, где и как ты его будешь ловить.
                                                                                                                                              Цитата Олег М @
                                                                                                                                              Насчёт наверняка уронили, это ты конечно загнул. И не замолчали, а, например, записали в лог и продолжили работу.
                                                                                                                                              В моём случае проблема в том, что когда я перехватываю исключение, то добавляю в лог ещё и file line, где оно было перехвачено. Через макросы это легко получается, а здесь будет проблематично.

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

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

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

                                                                                                                                              ошибка типа fatal
                                                                                                                                              Всё, приехали, дальше рельсы закончились. Всё сломалось, пришёл толстый писец. Пишем предсмертную записку в журнал. Прощаемся с пользователем и просим, чтоб он ни в чём, себя не винил. И завершаем процесс.
                                                                                                                                              Например в проге обнаружилась упоротая бага. Сломался главный модуль. Отвалился жёсткий диск. Ну или данные в памяти оказались повреждены до полной неузноваемости.
                                                                                                                                              Опять же ситуация исключительная, значит тоже исключения или альтернативные варианты, вроде terminate(), unexpected(), abort().

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

                                                                                                                                              Добавлено
                                                                                                                                              Цитата Олег М @
                                                                                                                                              Бросать его никто не мешает. Проблема в том, где и как ты его будешь ловить.

                                                                                                                                              Твой код выше, который из noexcept( false ) пытается сделать noexcept( true ).

                                                                                                                                              Добавлено
                                                                                                                                              Цитата Олег М @
                                                                                                                                              Цитата Eric-S @
                                                                                                                                              Когда ещё не слышал про scope_exit.

                                                                                                                                              Что это такое?

                                                                                                                                              Уже выше обсуждали.

                                                                                                                                              Цитата Олег М @
                                                                                                                                              Цитата Eric-S @

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

                                                                                                                                              Я такую штуку довольно активно использую
                                                                                                                                              Сообщение отредактировано: Eric-S -
                                                                                                                                                Цитата Eric-S @
                                                                                                                                                Твой код выше, который из noexcept( false ) пытается сделать noexcept( true ).

                                                                                                                                                Любой try-catch так делает
                                                                                                                                                  Цитата Олег М @
                                                                                                                                                  Цитата Eric-S @
                                                                                                                                                  Твой код выше, который из noexcept( false ) пытается сделать noexcept( true ).

                                                                                                                                                  Любой try-catch так делает

                                                                                                                                                  Ага. Любой делает. Но я намекаю на то, что с его распихиванием везде, надо бы аккуратнее, не увлекатся.
                                                                                                                                                  Сообщение отредактировано: Eric-S -
                                                                                                                                                    Цитата Eric-S @
                                                                                                                                                    У меня есть определёная стратегия обработки ошибок. Ну, где-то подсмотрел, где-то додумал. И никому не навязываю. Просто я думаю именно в рамках такой стратегии.

                                                                                                                                                    Это всё, конечно здорово, но у меня стратегия проще. Как у блондинки - либо есть исключение, либо его нет.
                                                                                                                                                    Если есть, то я, например всегда разрываю коннект с сервером, независимо от типа исключения. Потом восстанавливаю.

                                                                                                                                                    Но, это в любом случае дополнительный код, который можно было бы и не делать, если, например, обработчик объявлен как noexcept.

                                                                                                                                                    Добавлено
                                                                                                                                                    Цитата Eric-S @
                                                                                                                                                    Но я намекаю на то, что с его распихиванием везде, надо бы аккуратнее, не увлекатся.

                                                                                                                                                    Аккуратнее надо быть с noexcept(true). А с try-catch, по-барабану, можно и увлекаться. В определённых рамках естественно.
                                                                                                                                                      Цитата Олег М @
                                                                                                                                                      но у меня стратегия проще. Как у блондинки - либо есть исключение, либо его нет.
                                                                                                                                                      Если есть, то я, например всегда разрываю коннект с сервером, независимо от типа исключения. Потом восстанавливаю.


                                                                                                                                                      Эхе-хе... Не... Мы говорим всё не о том.
                                                                                                                                                      Вот ты рвёш подключение и востанавливаешь сеанс, когда выскакивает исключение. Любое исключение.
                                                                                                                                                      А у меня немного сложнее. Ряд исключений валят плагин и вообще всю программу. Ну, а от некоторых валится только плагин. Ибо, после некоторых исключений, например structured_exception, даже не знаю как востанавливать работу. Проще ещё раз запустить всю программу.

                                                                                                                                                      Сейчас подумал, что есть смысл, сделать специальные исключения, какое-нибудь warning_exception, которое будет ронять плагин, а главная прога автоматически запустит этот плагин. Ну... идея неплохая. Как-нибудь попробую.



                                                                                                                                                      Но я упоминул о стратегии обработки исключений, что к разным исключениям, нужно относится по разному.

                                                                                                                                                      Цитата Олег М @
                                                                                                                                                      Но, это в любом случае дополнительный код, который можно было бы и не делать, если, например, обработчик объявлен как noexcept.


                                                                                                                                                      Да, верно. Только ты же сам, написал, что с этим noexcept( true ) надо быть аккуратнее.
                                                                                                                                                      По-моему он допустим и правомочен только в достаточно простых и низкоуровневых функциях.
                                                                                                                                                      Там, где даже отбрасывание небольшого кусочка кода, даёт заметный прирост в производительности.
                                                                                                                                                      Там, где если возникнет исключение, то это наверняка кирдык всей программе.

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

                                                                                                                                                      Цитата Олег М @
                                                                                                                                                      Аккуратнее надо быть с noexcept(true). А с try-catch, по-барабану, можно и увлекаться. В определённых рамках естественно.


                                                                                                                                                      Ну... Это смотря где. На низком уровне noexcept( true ) предпочтительнее. А на высоком уровне try ... catch полезнее. Соответственно и наоборот. на высоком уровне noexcept( true ) мешает и гадит, а try ... catch на низком уровне тормозит и путает.
                                                                                                                                                        Я тут в офиге...

                                                                                                                                                        1. проставил noexcept в этих своих классах. По тестам всё нормуль.

                                                                                                                                                        2. Поскольку я проставлял в несколько заходов, переосмысливая, откатываясь, дописывая и переделывая другие функции, то noexcept записаны в разных стилях. Начал исправлять эти стили, приводя к единому.

                                                                                                                                                        3. переделываю, проверяю, сохраняю. Вроде всё нормально.

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

                                                                                                                                                        5. запускаю тест, а он у меня вдруг и говорит, что деструктор, ранее бывший noexcept( true ) внезапно стал noexcept( false )!

                                                                                                                                                        Упс! Приехали! Ничего себе побочный эффект! Осталось понять, откуда он такой злющий!

                                                                                                                                                        Я не знаю почему, но is_nothrow_destructible мне возвращал ложь в некоторых случаях.

                                                                                                                                                        Вот такую делал проверку:
                                                                                                                                                        static_assert( is_nothrow_destructible< someclass< stub_object, false > >::value, "noexcept destructor" );

                                                                                                                                                        1. проверяю влоб. Ставлю своему деструктору разные флаги.
                                                                                                                                                        ~someclass() noexcept( true ) {}
                                                                                                                                                        Проверку проходит успешно.
                                                                                                                                                        ~someclass() noexcept( false ) {}
                                                                                                                                                        Проверку ожидаемо заваливает.

                                                                                                                                                        2. указываю метод из базового класса.
                                                                                                                                                        ~someclass() noexcept( noexcept( unset() ) ) {}
                                                                                                                                                        Проверку заваливает.

                                                                                                                                                        3. кручу верчу модификатор у того метода:
                                                                                                                                                        void unset() noexcept( false ) {}
                                                                                                                                                        Проверку ожидаемо завалил.
                                                                                                                                                        void unset() noexcept( true ) {}
                                                                                                                                                        Проверку опять завалил.

                                                                                                                                                        Вариантов продолжения эксперементов было много, но я поленился их все колупать. Мне банально надоело!

                                                                                                                                                        Написал:
                                                                                                                                                        ExpandedWrap disabled
                                                                                                                                                          static_assert( noexcept( reinterpret_cast< someclass< stub_object, false >* >( 0 )->someclass< stub_object, false >::~someclass() ), "noexcept destructor" );

                                                                                                                                                        И оно сработало! Правильно сработало, без каких либо сомнений. Менял noexcept у деструктора, потом у метода unset, изменения отражались корректно.

                                                                                                                                                        Правда, там ещё был иной вариант синтаксиса, который меня умилил опупенно весёлой ошибкой.
                                                                                                                                                        ExpandedWrap disabled
                                                                                                                                                          static_assert( noexcept( reinterpret_cast< someclass< stub_object, false >* >( 0 )->~someclass() ), "noexcept destructor" );

                                                                                                                                                        Цитата

                                                                                                                                                        error C2068: недопустимое использование перегруженной функции. Отсутствует список аргументов?
                                                                                                                                                        note: Сообщение диагностики возникло в созданной компилятором функции "void *someclass<stub_object,false>::__delDtor(unsigned int) noexcept(<expr>)"


                                                                                                                                                        Аналогичную ошибку я получаю, если напишу:
                                                                                                                                                        ExpandedWrap disabled
                                                                                                                                                          static_assert( noexcept( (someclass< stub_object, false >()).~someclass() ), "noexcept destructor" );


                                                                                                                                                        Гы... Вот думаю, может я со своим извратом, опять чего-то начудил. Или же is_nothrow_destructible проверяет какие-то дополнительные свойства?
                                                                                                                                                        Наверное, надо как-то покопатся в нём и разобраться, как работает этот класс.
                                                                                                                                                        Сообщение отредактировано: Eric-S -
                                                                                                                                                          Цитата Eric-S @
                                                                                                                                                          Аналогичную ошибку я получаю, если напишу:

                                                                                                                                                          static_assert( noexcept( (someclass< stub_object, false >()).~someclass() ), "noexcept destructor" );

                                                                                                                                                          Для деструктора надо полностью имя прописывать

                                                                                                                                                          ExpandedWrap disabled
                                                                                                                                                            static_assert( noexcept( (someclass<stub_object, false>()).someclass<stub_object, false>::~someclass() ), "noexcept destructor" );


                                                                                                                                                          Цитата Eric-S @
                                                                                                                                                          reinterpret_cast< someclass< stub_object, false >* >( 0 )


                                                                                                                                                          Здесь, наверное, лучше использовать std::declval<someclass< stub_object, false >>().........
                                                                                                                                                            Цитата Олег М @
                                                                                                                                                            Для деструктора надо полностью имя прописывать

                                                                                                                                                            ExpandedWrap disabled
                                                                                                                                                              static_assert( noexcept( (someclass<stub_object, false>()).someclass<stub_object, false>::~someclass() ), "noexcept destructor" );

                                                                                                                                                            О! Не знал. Спасибо.
                                                                                                                                                            Но объявление конструктора мне ломает независимость проверки деструктора.
                                                                                                                                                            Если конструктор noexcept( false ), то провал.

                                                                                                                                                            Добавлено
                                                                                                                                                            Цитата Олег М @
                                                                                                                                                            Здесь, наверное, лучше использовать std::declval<someclass< stub_object, false >>().........

                                                                                                                                                            А вот так совсем чудненько
                                                                                                                                                            ExpandedWrap disabled
                                                                                                                                                              static_assert( noexcept( ( declval< someclass< stub_object, false > >() ).someclass< stub_object, false >::~someclass() ), "noexcept destructor" );
                                                                                                                                                              Забил бы ты на эти деструкторы. Исключения в них это экзотика, а усилий тратишь кучу
                                                                                                                                                                Цитата Олег М @
                                                                                                                                                                Забил бы ты на эти деструкторы. Исключения в них это экзотика, а усилий тратишь кучу

                                                                                                                                                                Уже всё. Отвлёкся вот на пару минут, для коррекции кода и написании ответа и пошёл заниматся другими делами.

                                                                                                                                                                У меня в todo list большой список пунктов. А за эту ночь, я его сократил на 6 пунктиков.
                                                                                                                                                                И ни один из них не косался деструкторов и noexcept.
                                                                                                                                                                  Цитата Eric-S @
                                                                                                                                                                  static_assert( noexcept( (someclass<stub_object, false>()).someclass<stub_object, false>::~someclass() ), "noexcept destructor" );

                                                                                                                                                                  О! Не знал. Спасибо.
                                                                                                                                                                  Но объявление конструктора мне ломает независимость проверки деструктора.
                                                                                                                                                                  Если конструктор noexcept( false ), то провал

                                                                                                                                                                  Это потому что ты перед вызовом деструтора вызывал конструктор
                                                                                                                                                                    Цитата Олег М @
                                                                                                                                                                    а усилий тратишь кучу

                                                                                                                                                                    Ну, зато вот всякое интересное узнал по ходу. Да ещё пару косвенных багов откопал, которые мог бы и не заметить. Так что нормуль, остался с двойным профитом и чувством удовлетворения.

                                                                                                                                                                    Добавлено
                                                                                                                                                                    Цитата Олег М @
                                                                                                                                                                    потому что ты перед вызовом деструтора вызывал конструктор

                                                                                                                                                                    Угу. Догадался сразу. Поэтому и проверку сделал.
                                                                                                                                                                    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                                                                                                                                    0 пользователей:


                                                                                                                                                                    Рейтинг@Mail.ru
                                                                                                                                                                    [ Script execution time: 0,2038 ]   [ 17 queries used ]   [ Generated: 26.04.24, 22:35 GMT ]