Можно ли освободить память в деструкторе, если они выделяют память в частной функции в C ++? - PullRequest
3 голосов
/ 25 июля 2011

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

class Simulation{
private:
    int initial_call; //a flag used to initialize memory
    double *TransferTracker;
public:
    Simulation();
    ~Simulation();
    void calc();
};

Simulation simulator; //global instance of Simulation

Simulation::Simulation()
{
   initial_call = 1;
}
Simulation::~Simulation()
{
    //when calling the destructor, though, the address is
    //0xcccccccc and the following attempt to delete produces
    //the compiler error.
    delete [] TransferTracker; //see error
}
void Simulation::calc()
{
    for (int i = 0; i < num_its; i++)
    {
         if (initial_call)
         {
             TransferTracker = new double [5];
             //The address assigned is, for example, 0x004ce3e0
             initial_call = 0;
         }
    }
    //even if this calc function is called multiple times, I see
    //that the address is still 0x004ce3e0.
}

Ошибка, которую я получаю из приведенного выше фрагмента кода:

 Unhandled exception at 0x5d4e57aa (msvcr100d.dll) in LRGV_SAMPLER.exe: 0xC0000005: Access    
 violation reading location 0xccccccc0.

Эта ошибка имеет смысл, поскольку при входе в деструктор я проверял адрес памяти TransferTracker.У меня вопрос, почему мы теряем адрес при входе в деструктор?Вероятно, это как-то связано с тем, что симулятор является глобальным;эта парадигма, кажется, работает хорошо, если класс не был глобальным.Я новичок в объектно-ориентированном программировании, поэтому любая помощь приветствуется!

РЕДАКТИРОВАТЬ: Это было в основном ошибкой с моей стороны и помогли ответы.Возникли две проблемы: (1) указатели никогда не были установлены в NULL, что создавало путаницу при попытке удалить нераспределенные указатели.(2) На самом деле в моей области видимости было два экземпляра класса, что было ошибкой с моей стороны.В конечном коде будет только один экземпляр.Спасибо всем!

Ответы [ 3 ]

5 голосов
/ 25 июля 2011

Инициализируйте указатель на NULL (0)

Simulation::Simulation() : TransferTracker(NULL)
{
  initial_call = 1;
}
Simulation::~Simulation()
{
  //when calling the destructor, though, the address is
  //0xcccccccc and the following attempt to delete produces
  //the compiler error.
  if(TransferTracker) delete [] TransferTracker; //see error
  TransferTracker = NULL;
}

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

РЕДАКТИРОВАТЬ:

void Simulation::calc()
{
    for (int i = 0; i < num_its; i++)
    {
         if (initial_call)
         {
             if(TransferTracker) delete []  TransferTracker;
             TransferTracker = new double [5];
             initial_call = 0;
         }
    }
}
3 голосов
/ 25 июля 2011

Вы должны инициализировать значение переменной экземпляра TransferTracker до 0 в конструкторе.Проблема, с которой вы столкнулись, заключается в уничтожении класса Simulation без фактического присвоения динамической памяти TransferTracker.

Вызов delete[] в деструкторе с нулевым указателем является безопасным.Проблема в том, что если вы не дадите значение TransferTracker, оно может иметь любое неопределенное значение, что вызовет проблемы при попытке освободить его с delete[].

EDIT :

Согласно вашему редактированию, как вы можете гарантировать, что существует только один экземпляр класса Simulation?Это связано с тем, что вы включили несколько файлов .o в свою сборку и т. Д.

1 голос
/ 25 июля 2011

Я подозреваю, что причина в том, что ваш деструктор вызывается, когда вы еще не вызывали функцию calc(), поэтому память еще не распределена.

Вы хотите установить «охранник», который будет гарантировать, что вы уже выделили память, прежде чем пытаться освободить память для TransferTracker.

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