Утечка памяти, как найти и удалить - PullRequest
0 голосов
/ 23 сентября 2018

Я использую счетчик утечек памяти в моем проекте, и он говорит, что 2 из моих 4 выделений просочились.Я думаю, что нашел их, но не уверен, и даже не знаю, как их перемещать.Два являются членами, m_color и m_data, и два являются параметрами для этих элементов, один в m_color и один в m_data.

class Screen {
public:
    Screen(uint16_t width, uint16_t height)
        : m_width(width), m_height(height),
          m_size(width*height), m_color(new TerminalColor[m_size]), <-?
          m_data(new char[m_size]) <-?
    {}
    ~Screen(){}
    void clear();
    void fill(char ch, const TerminalColor &color);
    void fillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char ch, const TerminalColor &color);
    void set(uint16_t x, uint16_t y, char ch, const TerminalColor &color);
    void setText(uint16_t x, uint16_t y, const std::string& text,  const TerminalColor &color);
    void setTextRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const std::string& text,  const TerminalColor &color);
    void draw(Terminal &terminal);
private:
    const uint16_t m_width;
    const uint16_t m_height;
    const uint32_t m_size;
    TerminalColor *m_color; <-?
    char *m_data; <-?
};

Это члены, которые просочились, так как я не могу удалить их после того, как я вставил впараметры?Как их переместить, если так?

1 Ответ

0 голосов
/ 23 сентября 2018

Причина утечки в том, что конструктор Screen динамически распределяет память, используя два выражения new, а соответствующее выражение delete отсутствует.

По этой причине простоефункция типа

 void f()
 {
      Screen x(some_width, some_height);
         // x is destructed as f() returns
 }

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

Одним из решений является добавление соответствующих выражений delete в деструкторНапример, (в пределах определения класса)

 ~Screen()
 {
     delete [] m_color;
     delete [] m_data;
 };

Имейте в виду, что у класса могут быть другие конструкторы - и некоторые конструкторы автоматически генерируются компилятором, если вы не предотвращаете это (чего у вас нет).Необходимо обеспечить, чтобы все конструкторы выделяли память одинаковым образом, чтобы избежать неопределенного поведения.Например, сгенерированный по умолчанию конструктор копирования будет копировать указатели, а не делать динамическое выделение памяти.Поэтому его использование приводит к двум экземплярам Screen, содержащим указатели на одну и ту же динамически распределенную память.Когда оба объекта впоследствии будут уничтожены, общая память будет освобождена дважды.Тогда поведение не определено.

Лучшим вариантом является избегать использования необработанных указателей и использовать стандартные контейнеры.Например, присвойте m_color тип std::vector<TerminalColor> и m_data тип std::vector<char> и инициализируйте их в конструкторе, используя что-то вроде

Screen(uint16_t width, uint16_t height)
    : m_width(width), m_height(height),
      m_size(width*height),
      m_color(m_size),      // initialise m_color to have m_size elements
      m_data(m_size)        // initialise m_data to have m_size elements
{}

Преимущество использования стандартных контейнеров заключается в том, что вам не нужносделать что-нибудь в деструкторе Screen s, потому что память будет освобождена автоматически.Это также гарантирует, что другие конструкторы воспроизводятся правильно (т.е. избегают утечек памяти), если вы не сделаете все возможное, чтобы изменить поведение этих конструкторов

Я выбрал std::vector в качестве стандартного типа контейнера.В зависимости от потребностей, вы можете использовать другие типы контейнеров.

Один из компромиссов с использованием std::vector заключается в том, что вам МОЖЕТ потребоваться внести незначительные изменения в способ доступа к элементам массивов (например, если вам нужночтобы передать указатель на первый элемент m_color функции, ожидающей массив, передайте &m_color[0] вместо m_color), но эти настройки просты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...