Стек разматывает динамически созданный объект, конструктор которого также действует на кучу

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

class bla
{
private:
double *data;
int size;

public:
bla(int s)
{
size = s;
data = new double [size];
}
~bla()
{
delete[] data;
}
}

и у меня есть функция, например

void f(bool huge)
{
bla *ptr;
if (huge)
ptr = new bla(1e10);
else
ptr = new bla(1e2);

//...

delete ptr;
}

Что произойдет, если распределение ptr = new bla(1e10) является успешным (это означает, data а также size выделено) но не конструктор -> он выбрасывает исключение, потому что 1e10 слишком велик? У меня нет утечки памяти с data = new double [size], но у меня утечка памяти с еще существующим double *data а также int size в кучу? Или они очищаются при разматывании стека?

Должен ли я написать это лучше так?

void f(bool huge)
{
bla *ptr = 0;
try { ptr = new bla(1e10); }
catch (...) { delete ptr; throw; }
}

а также

class bla
{
private:
double *data = 0;
// ... to not have an delete[] on a non-0 pointer
}

редактировать:

Немного более сложный пример, чтобы проиллюстрировать templatetypedefs anwswer:

#include <iostream>

using namespace std;

class bla2
{
private:
double *data;

public:
bla2 ()
{
cout << "inside bla2 constructor, enter to continue";
cin.get();
data = new double [2*256*256*256];
}
~bla2 ()
{
cout << "inside bla2 destructor, enter to continue";
cin.get();
delete[] data;
}
};

class bla
{
private:
bla2 data1;
double data2[2*256*256*256];
double *data3;

public:
bla ()
{
cout << "inside bla constructor, enter to continue";
cin.get();
data3 = new double [8*256*256*256]; // when only 1/4 as much -> then all success
}
~bla ()
{
cout << "inside bla destructor, enter to continue";
cin.get();
delete[] data3;
}
};

void main()
{
bla *a;
cout << "program start, enter to continue";
cin.get();
try { a = new bla; }
catch (...) { cout << "inside catch, enter to continue"; cin.get(); exit(EXIT_FAILURE); }
cout << "success on a, enter to continue";
cin.get();
delete a;
}

С помощью этого примера я могу хорошо видеть на своей машине (Win7 4GB RAM) относительно монитора ресурсов, как он идет первым внутри bla2() затем bla() но тогда из-за сбоя выделения data3 первые звонки ~bla2() а потом заканчивается (без ~bla()) в catch(...) с памятью на базовом уровне, как при запуске программы.

Когда я устанавливаю количество элементов data3 только на 1/4, тогда все удаляются, с ожидаемым порядком вызова конструкторов и деструкторов.

1

Решение

В C ++, если объект создан new если его конструктор выдает исключение, то язык гарантирует, что память, выделенная для самого объекта, будет освобождена. Это означает, что вы не должны перехватывать исключение и освобождать память, так как память уже была освобождена, и вы получите неопределенное поведение.

Если конструктор выдает исключение, то деструктор объекта не быть призван. В вашем случае это не проблема — если внутреннее распределение завершится неудачно, память, зарезервированная для массива, будет очищена, а исключение распространится наружу. Вам не нужно делать что-то необычное. Однако, если у вас есть несколько распределений, вы, вероятно, захотите добавить обработку исключений внутри конструктора чтобы отловить любые ошибки выделения и освободить соответствующим образом.

Тем не менее, есть гораздо более простое решение: не используйте new[] а также delete[] выделить массив. Вместо этого используйте std::vector, который обрабатывает все свои собственные распределения и освобождения и не требует няни с вашей стороны. 🙂

Надеюсь это поможет!

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]