Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.238.142.134] |
|
Сообщ.
#1
,
|
|
|
Добрый вечер. Собственно вопрос: "есть некий код, хочу понять есть ли так утечка памяти?". Код ниже.
const char *ArgsParseException::what() const throw() { return strcpy(new char[errorMessage_.size()], errorMessage_.c_str());//FIXME memory leak } |
Сообщ.
#2
,
|
|
|
Мало данных. Если new бросит исключение, то будет вызвана unexpected()-функция, которая по дефолту вызывает terminate() (которая по дефолту implementation defined, будет ли она разматывать стек). В процессе завершения приложения уже неважно, что там будет с блоком хипа, но в любом случае неудачное распределение памяти должно оставить хип без изменений. Хуже, что если дефолтовые unexpected() или terminate() переопределены, то это уже может играть свою роль. В случае unexpected() только от реализации её самой зависит, что дальше будет с кодом. (В случае terminate() завершение приложения неизбежно.)
В случае, если new исключений не бросает, других исключений быть не должно, но есть ненулевая вероятно, что errorMessage_ может преподнести сюрпризы, из кода ибо непонятно, что это за хрень. |
Сообщ.
#3
,
|
|
|
Qraizer, может так понятнее будет
.h /** * @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 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 } |
Сообщ.
#4
,
|
|
|
Утечка может иметь место по другой причине. Возвращая const char*, указывающий на новый блок в хипе, ArgsParseException::what() (есть большое подозрение, что это некий потомок std::exception) не может ничего поделать с распределённым new блоком, поэтому его утилизация ложится на плечи кого-то ещё. Он есть?
|
Сообщ.
#5
,
|
|
|
Ну да, см.выше. Проблема в том, что если тупо возвращать
errorMessage_.c_str() значение не копируется и, вполне понятно почему. Ловим исключения так: 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; } |
Сообщ.
#6
,
|
|
|
Цитата kotmatroskin55 @ В данных реалиях я вообще не понимаю, зачем понадобился новый блок памяти взамен уже имеющегося внутри std::string. может так понятнее будет ... |
Сообщ.
#7
,
|
|
|
При попытке вернуть указатель на содержимое строки возвращается либо мусор, либо ничего. Не пойму где я затупил.
|
Сообщ.
#8
,
|
|
|
P.S.
Цитата kotmatroskin55 @ Утечка в catch{}. Где освобождение выделенного .what() блока? Ловим исключения так: |
Сообщ.
#9
,
|
|
|
Qraizer с утра, на свежую голову посмотрю. Спасибо. Но для меня, все же, загадка, почему при попытке вернуть указатель на содержимое строки возвращается либо мусор, либо ничего?
Добавлено Закостылил 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, я правильно понял идею? |
Сообщ.
#10
,
|
|
|
Цитата kotmatroskin55 @ Закостылил Возможно, это поможет в этот раз. А в следующий ? Если уж ты принял решение самостоятельно использовать пару new/delete, тогда надёжнее будет смастерить класс, который будет получать ресурс и следить за его правильным возвращением. Предоставляя его всем нуждающимся. Тогда проблема с утечками резко упростится. |
Сообщ.
#11
,
|
|
|
ЫукпШ, а какие есть варианты?
|
Сообщ.
#12
,
|
|
|
Цитата kotmatroskin55 @ ЫукпШ, а какие есть варианты? kotmatroskin55, варианты есть разные. Можно сделать класс реализующий нужды именно этого проекта. Это не очень удачный вариант, но можно с него начать. Лучше сделать шаблонный класс. Его методы, вероятно будут такие: Alloc, Free, operator[], GetPointer, GetSize, MemSet итп итд Вариантов названий класса много, но лучше если имя класса не будет совпадать с именем стандартного библиотечного класса. Например, "CMemT". ----- Что касается поиска утечек памяти new/delete, то достаточно их перегрузить и таким образом сделать не сложный измерительный инструмент. Но вполне работоспособный. |
Сообщ.
#13
,
|
|
|
Цитата kotmatroskin55 @ Понятия не имею. Вероятно, есть ещё implementation defined или undefined поведения. Например, где-то не включён заголовок <string>.Но для меня, все же, загадка, почему при попытке вернуть указатель на содержимое строки возвращается либо мусор, либо ничего? Цитата kotmatroskin55 @ В целом да. Но это криво. Стоит тебе поменять реализацию своего ArgsParseException, и его контракты могут измениться. Отслеживать подобное в своих – а тем более чужих – проектах то ещё удовольствие.я правильно понял идею? В тему о правильном подходе. По Стандарту класс std::exception имеет синопсис namespace std { class exception { public: exception() noexcept; exception(const exception&) noexcept; exception& operator=(const exception&) noexcept; virtual ~exception(); virtual const char* what() const noexcept; }; } Ты можешь избежать всех сложностей, просто изменив предка на какой-нибудь std::logic_error() ну или что там больше подходит. Во-первых, он уже принимает std::string, во-вторых, у него есть .what(), который полностью должен тебя удовлетворить. Вообще, всю заботу о реализации берёт на себя <stdexcept>. Причём заметь, в конструкторе того же std::logic_error() никакого throw() или там noexcept уже нет. |
Сообщ.
#14
,
|
|
|
Цитата Qraizer @ Ты можешь избежать всех сложностей, просто изменив предка на какой-нибудь std::logic_error() ну или что там больше подходит. Qraizer, Так и поступил, спасибо. |
Сообщ.
#15
,
|
|
|
Цитата 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() и всё будет хорошо. |