На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Memory leak?
    Добрый вечер. Собственно вопрос: "есть некий код, хочу понять есть ли так утечка памяти?". Код ниже.
    ExpandedWrap disabled
      const char *ArgsParseException::what() const throw() {
                  return strcpy(new char[errorMessage_.size()], errorMessage_.c_str());//FIXME memory leak
              }
      Мало данных. Если new бросит исключение, то будет вызвана unexpected()-функция, которая по дефолту вызывает terminate() (которая по дефолту implementation defined, будет ли она разматывать стек). В процессе завершения приложения уже неважно, что там будет с блоком хипа, но в любом случае неудачное распределение памяти должно оставить хип без изменений. Хуже, что если дефолтовые unexpected() или terminate() переопределены, то это уже может играть свою роль. В случае unexpected() только от реализации её самой зависит, что дальше будет с кодом. (В случае terminate() завершение приложения неизбежно.)
      В случае, если new исключений не бросает, других исключений быть не должно, но есть ненулевая вероятно, что errorMessage_ может преподнести сюрпризы, из кода ибо непонятно, что это за хрень.
        Qraizer, может так понятнее будет
        .h
        ExpandedWrap disabled
                  /**
                   * @class ArgsParseException - my exception
                   */
                  class ArgsParseException : public std::exception {
                  public:
                      /**
                       * @brief ArgsParseException  - constructor
                       * @param message - error message
                       */
                      explicit ArgsParseException(const std::string &message) throw();
           
                      /**
                       * @brief what - override method
                       * @return copy of error message
                       */
                      const char *what() const throw() override;
           
                  private:
                      const std::string errorMessage_;
                  };

        .cpp
        ExpandedWrap disabled
                  ArgsParseException::ArgsParseException(const std::string &message)  throw()
                          : errorMessage_(message) {}
           
                  const char *ArgsParseException::what() const throw() {
                      return strcpy(new char[errorMessage_.size()], errorMessage_.c_str());//FIXME memory leak
                  }
          Утечка может иметь место по другой причине. Возвращая const char*, указывающий на новый блок в хипе, ArgsParseException::what() (есть большое подозрение, что это некий потомок std::exception) не может ничего поделать с распределённым new блоком, поэтому его утилизация ложится на плечи кого-то ещё. Он есть?
            Ну да, см.выше. Проблема в том, что если тупо возвращать
            ExpandedWrap disabled
               errorMessage_.c_str()

            значение не копируется и, вполне понятно почему.
            Ловим исключения так:
            ExpandedWrap disabled
              int main(int argc, char *argv[]) {
                  try {
                      auto parser = std::make_shared<ArgumentParser>();
                      auto commandHandler = std::make_shared<CommandHandler>();
                      parser->startParsing(argc, argv);
                  }
                  catch (ArgsParseException &e) {
                      std::cout << e.what() << std::endl;
                  }
                  return 0;
              }
              Цитата kotmatroskin55 @
              может так понятнее будет
              ...
              В данных реалиях я вообще не понимаю, зачем понадобился новый блок памяти взамен уже имеющегося внутри std::string.
                При попытке вернуть указатель на содержимое строки возвращается либо мусор, либо ничего. Не пойму где я затупил.
                  P.S.
                  Цитата kotmatroskin55 @
                  Ловим исключения так:
                  Утечка в catch{}. Где освобождение выделенного .what() блока?
                    Qraizer с утра, на свежую голову посмотрю. Спасибо. Но для меня, все же, загадка, почему при попытке вернуть указатель на содержимое строки возвращается либо мусор, либо ничего?

                    Добавлено
                    Закостылил
                    ExpandedWrap disabled
                      try {
                              auto parser = std::make_shared<ArgumentParser>();
                              auto commandHandler = std::make_shared<CommandHandler>();
                              parser->startParsing(argc, argv);
                          }
                          catch (ArgsParseException &e) {
                              std::cout << e.what() << std::endl;
                              delete e.what();
                          }


                    Добавлено
                    Цитата kotmatroskin55 @
                    Утечка в catch{}. Где освобождение выделенного .what() блока?


                    Qraizer, я правильно понял идею?
                      Цитата kotmatroskin55 @
                      Закостылил

                      Возможно, это поможет в этот раз.
                      А в следующий ?
                      Если уж ты принял решение самостоятельно использовать пару new/delete,
                      тогда надёжнее будет смастерить класс, который будет получать ресурс
                      и следить за его правильным возвращением. Предоставляя его всем нуждающимся.
                      Тогда проблема с утечками резко упростится.
                        ЫукпШ, а какие есть варианты?
                          Цитата kotmatroskin55 @
                          ЫукпШ, а какие есть варианты?

                          kotmatroskin55, варианты есть разные.
                          Можно сделать класс реализующий нужды именно этого проекта.
                          Это не очень удачный вариант, но можно с него начать.
                          Лучше сделать шаблонный класс.
                          Его методы, вероятно будут такие:
                          Alloc, Free, operator[], GetPointer, GetSize, MemSet итп итд
                          Вариантов названий класса много, но лучше если имя класса не будет
                          совпадать с именем стандартного библиотечного класса.
                          Например, "CMemT".
                          -----
                          Что касается поиска утечек памяти new/delete, то достаточно их перегрузить
                          и таким образом сделать не сложный измерительный инструмент.
                          Но вполне работоспособный.
                          Сообщение отредактировано: ЫукпШ -
                            Цитата kotmatroskin55 @
                            Но для меня, все же, загадка, почему при попытке вернуть указатель на содержимое строки возвращается либо мусор, либо ничего?
                            Понятия не имею. Вероятно, есть ещё implementation defined или undefined поведения. Например, где-то не включён заголовок <string>.
                            Цитата kotmatroskin55 @
                            я правильно понял идею?
                            В целом да. Но это криво. Стоит тебе поменять реализацию своего ArgsParseException, и его контракты могут измениться. Отслеживать подобное в своих – а тем более чужих – проектах то ещё удовольствие.

                            В тему о правильном подходе. По Стандарту класс std::exception имеет синопсис
                            ExpandedWrap disabled
                              namespace std {
                                class exception {
                                public:
                                  exception() noexcept;
                                  exception(const exception&) noexcept;
                                  exception& operator=(const exception&) noexcept;
                                  virtual ~exception();
                                  virtual const char* what() const noexcept;
                                };
                              }
                            Ты видишь тут exception(const char*) или кто-то похожее? Я нет. Отсюда следует, что если ты в производном классе вводишь конструкции для подобного, то noexcept ака throw() твоя личная гарантия, которую ты как хочешь, так и реализуй. Ты использовал ArgsParseException(const std::string&) throw(), твоё право, но будь добр, озаботься гарантией throw() сам, ибо std::string в своих конструкторах копии её не предоставляет, а ведь именно он используется в инициализаторе errorMessage_(message), т.к. ArgsParseException::errorMessage_ является полем-значением.
                            Ты можешь избежать всех сложностей, просто изменив предка на какой-нибудь std::logic_error() ну или что там больше подходит. Во-первых, он уже принимает std::string, во-вторых, у него есть .what(), который полностью должен тебя удовлетворить. Вообще, всю заботу о реализации берёт на себя <stdexcept>. Причём заметь, в конструкторе того же std::logic_error() никакого throw() или там noexcept уже нет.
                              Цитата Qraizer @
                              Ты можешь избежать всех сложностей, просто изменив предка на какой-нибудь std::logic_error() ну или что там больше подходит.


                              Qraizer, Так и поступил, спасибо.
                                Цитата kotmatroskin55 @
                                        const char *ArgsParseException::what() const throw() {
                                            return strcpy(new char[errorMessage_.size()], errorMessage_.c_str());//FIXME memory leak
                                        }


                                Тут есть ещё один косяк, помимо всех прочих. Ты не выделяешь память под завершающий ноль, но strcpy записывает его. Надо делать new char[errorMessage_.size() + 1].
                                А вообще, здесь достаточно сделать return errorMessage_.c_str() и всё будет хорошо.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


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