Написание контрольного примера, который проверяет утечки памяти в C ++ - PullRequest
1 голос
/ 16 декабря 2009

ПРИМЕЧАНИЕ: ЭТО НЕ РАБОТАЕТ С ЭТОЙ ПРАКТИЧЕСКИМ ЭКЗАМЕНОМ, предоставленным нам НАШИМИ ПРОФЕССОРАМИ, ЧТОБЫ ПОМОЧЬ НАМ ПОДГОТОВИТЬСЯ К НАШЕМУ ЭКЗАМЕНУ

Я сейчас учусь на экзамен по программированию. На одном из тестов, которые нам дали, у нас есть следующий вопрос:

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

template <typename T>
class Container {
   public:
      void insert(T *op);
      // EFFECTS: inserts the object pointed to by op into
      // the container
      T *remove();
      // EFFECTS: removes an object from the Container, and
      // returns a pointer to it. Returns NULL if no
      // objects remain in the Container.
      // Note: the implementation can choose which
      // object to return if more than one exists.
      Container(); // ctor
      Container(const Container &l); // copy ctor
      Container &operator=(const Container &l); // assignment
      ~Container(); // dtor
   private:
      ...
};

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

Вы подозреваете, что реализация деструктора не удовлетворяет правилу сохранения инварианта At-Most-Once, и вместо этого происходит утечка памяти. Напишите приемочный тест (аналогичный тесту в проекте 4), чтобы проверить это условие. Вы должны предоставить подходящий тип содержимого и основную сеть, которая выполняет проверку.

Обратите внимание, что вы не можете зависеть от поведения, которое язык оставляет неопределенным, вы не можете Предположим, что у вас есть альтернативный распределитель из Project 5, и вы не можете переопределить оператор удаления. Подсказка: вам разрешено использовать глобальную переменную.

Я хоть что-то вроде:

#include <iostream>

using namespace std;

int *p = NULL;

void leak() {
    int *num = new int(5);
    p = num;
    delete num;
}

int main() {
    if ((*p = 6)) {
        cout << "Memory leak\n";
    } else {
        cout << "No Leak\n";
    }
}

Основная идея заключается в том, что я не мог записать в пространство памяти, которое я не выделил. При компиляции этого тестового кода, хотя он работает просто отлично, очевидно, вы можете Любые идеи о том, как написать такой контрольный пример?

Ответы [ 6 ]

5 голосов
/ 16 декабря 2009

Когда вы говорите:

void leak() {
    int *num = new int(5);
    p = num;
    delete num;
}

нет утечки памяти. Тем не менее, имеется висячий указатель (p), который будет вызывать поведение без защиты при разыменовании.

4 голосов
/ 17 декабря 2009

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

 class InstCounter {
 public:
   static int counter;
   InstCounter() { counter++; }
   ~InstCounter() { counter--; }
 };
 int InstCounter::counter = 0;

 int main(int argc, char** argv)
 {
   { Container<InstCounter> c;
     // insert elements...
     c.insert(new InstCounter);
   } // calls dtor of c
   if (InstCounter::counter > 0)
     std::cout << "Container is leaking." << std::endl;
   return 0;
 }
4 голосов
/ 16 декабря 2009

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

Затем вы можете выполнить любые необходимые тесты для контейнера (создать его, заполнить и очистить, удалить и т. Д.) И проверить на утечки памяти, проверив, что глобальная переменная равна 0 после того, как контейнер был уничтожен.

0 голосов
/ 16 декабря 2009

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

0 голосов
/ 16 декабря 2009

Вы можете увеличить целочисленную глобальную переменную в конструкторе T и уменьшить ее в деструкторе T: при этом вы узнаете, уничтожаются ли экземпляры T контейнером. Приемочный тест может выделить несколько экземпляров T в экземпляр Container, уничтожить Container и проверить, уничтожил ли он экземпляры T (то есть были ли вызваны деструкторы T).

Не переопределяя оператор удаления, я не вижу простого способа определить, уничтожает ли контейнер не только экземпляры T, но и освобождает ли память, которую занимают экземпляры T: но если он равен , уничтожает T экземпляры (которые вы можете проверить, как упомянуто в первом параграфе выше), тогда вы можете надеяться, что , вероятно, также освобождает память, занятую каждым экземпляром.

0 голосов
/ 16 декабря 2009

Я не уверен, что указано в Project 4 и Project 5, но я думаю, что способ сделать это - назначить глобальный указатель (согласно подсказке) на объект, который вы вставляете в контейнер. Если вы затем уничтожите контейнер, он должен уничтожить объекты внутри него, и этот глобальный указатель должен теперь быть нулевым.

...