Распределение кучи и стека

Я немного путаюсь по теме выделения объектов в куче против выделения на стеке и когда и как следует вызывать delete().

Например, у меня есть класс Vector. Я хотел бы создать массив из них.

Я мог бы сделать это

Vector** v = new Vector*[100]; //create an array of 100 pointers to 100 Vector objects

Это, как я понял, выделил бы все (ну кроме указателей адресов) на кучу? Поэтому для свободной памяти мне нужно:

for (int i = 0; i < 100; ++i)
{
   delete(v[i]);
}
delete(v);

ИЛИ просто

delete(v);

достаточно?

Теперь еще один пример:

Vector* v = Vector[100];

Что происходит в этом случае? Где происходит распределение? Куча или стек? Мне еще нужно позвонить

delete(v);

Но это не все вопросы, извините за длинный пост.

Пример:

class Vector
{
  int x, y, z;
}

Vector* v = new Vector();

где x, y, z выделены? Куча или стек?

или как об этом:

class Vector2
{
   int items[10];
}

Vector2* v2 = new Vector2();

где выделены пункты [10]? Как удалить v2? Нужен ли мне индивидуальный деструктор?

И последнее, но не менее важное: об этом:

class Vector3
{
   int* items;
}

Vector3 v3 = Vector3();

Где хранится указатель на элементы? кучу или стек? Как удалить это?

Спасибо и извините за длинный вопрос. У меня были проблемы с этим материалом в течение длительного времени, и я не мог найти полное объяснение на линии.

Ответ 1

Я начну с самого начала...

Vector** v = new Vector*[100];

Выделяет массив из 100 указателей на объекты типа Vector в куче Он возвращает один указатель v, который вы можете использовать для отслеживания этого массива указателей.

Удалите этот массив из 100 пунктов с помощью:

delete[] v;

(Используйте delete operator- delete для одного выделенного объекта, delete[] для массива)

Следующий случай (я предполагаю, что вы имеете в виду new Vector[100]:

Vector* v = new Vector[100];

Вы выделили массив из 100 векторов в куче и получили указатель на его начальное местоположение - v. Удалите этот массив с помощью:

delete[] v;

Далее...

class Vector
{
  int x, y, z;
}

Vector* v = new Vector();

Это выделяет объект класса Vector в куче и дает указатель на его отслеживание. Поскольку вы выделили весь объект в куче, x, y и z все выделены в куче.

Удалите его с помощью

delete v;


class Vector2
{
   int items[10];
}

Vector2* v2 = new Vector2();

Это немного сложнее, но я собираюсь это обосновать...

Классы - это чертежи. Вы вообще не выделили какую-либо память, пока не создадите экземпляр класса каким-то образом, в данном случае в куче. Поскольку класс является планом, items не может быть выделен до тех пор, пока вы не создадите объект класса Vector2 в куче. Я думаю, что мы можем разумно заключить, что items распределяется таким образом в куче.

Удалить v2 с помощью:

delete v2;

И наконец:

class Vector3
{
   int* items;
}

Vector3 v3 = Vector3();

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

Ответ 2

Отключается, что вам, вероятно, не нужно динамически выделять что-либо.
Либо статический массив, либо вектор будут работать намного лучше.

Но давайте предположим, что вы делаете это как учебное упражнение.

1 Выделение массива указателей

Vector** v = new Vector*[100]; //create an array of 100 pointers to 100 Vector objects
                               //
                               // The above comment is misleading.
                               // The 100 pointers have not been initialized.

Это выделило область памяти, у которой есть место для 100 указателей (к Vector (обратите внимание, что они неинициализированы, т.е. каждый указатель случайным образом)). Чтобы удалить это, вам нужно сделать:

delete [] v;

2 Выделение элементов массива

Если вы выделите каждого из членов (что вы должны сделать, если вы хотите их использовать:

for (int i = 0; i < 100; ++i)
{
   v[i] = new Vector;
}

// Code

for (int i = 0; i < 100; ++i)
{
   delete v[i];
}

Обратите внимание, что для каждого вызова нового должен быть соответствующий вызов для удаления.

3 ОШИБКА

Vector* v = Vector[100];

Это просто неправильно. Если не будет компилироваться.

4 Куда идут участники

Если элемент не является указателем, он находится внутри объекта.
Если элемент является указателем, он должен быть выделен отдельно.

class Vector
{
  int x, y, z;
}

Vector* v1 = new Vector();
Vector  v2 = Vector();      // Yes the = Vector() is required

Здесь v1 указывает на динамически выделенный объект, содержащий x/y/z
Здесь v2 - объект, содержащий x/y/z

Я знаю, что люди собираются сказать, что = Vector(); не требуется или построена копия. Оба типа истины, но оба не имеют смысла. 1) Его построение копии, но компилятор всегда достаточно умен, чтобы удалить его. 2) Необходимо сделать его эквивалентным линии выше. Разница заключается в отсутствии default-initialized (т.е. Не инициализации), с которой члены zero-initialized (потому что Vector() имеет только сгенерированный компилятором конструктор).

А как насчет элементов массива.
Они ничем не отличаются от других членов. Участники ВСЕГДА выделяются внутри объекта. Если элемент является указателем, то он находится внутри объекта, но то, на что он указывает, должно быть явно задано.

class Bob
{
    int   dataArray[10];
    int*   dataPtr;
};
Bob  b1 = Bob();
Bob* b2 = new Bob();

b1.dataArray[0] = 1;            // dataArray is inside the object.
                                // b1 is allocated locally

b1.dataPtr      = new int [10]; // dataPtr is inside the object.
                                // But what it points at must be seprotally defined.
                                // Note you must call delete [] for each new []
b1.dataPtr[5] = 2;

b2->dataArray[0] = 1;           // dataArray is inside the object.
                                // b2 is allocated dynamically

b2->dataPtr      = new int [10];// dataPtr is inside the object.
                                // But what it points at must be aseptically defined.
                                // Note you must call delete [] for each new []
b2->dataPtr[5] = 2;

Ответ 3

Общее правило:

  • когда вы используете new или new [], вы выделяете кучу, в другом случае вы выделяете на стек.

  • каждый раз, когда вы используете new, вы должны использовать delete (явно или не)

  • каждый раз, когда вы используете new[], вы должны использовать delete[] (явно или не)

Следующий код - UB, так как вы используете один новый [] и 101 delete. Используйте один delete[].

Vector** v = new Vector*[100];
for (int i = 0; i < 100; ++i)
{
   delete(v[i]);
}
delete(v);

Ответ 4

  • delete [] v; - это обозначение массива оператора delete. Вы должны использовать его при удалении массивов, вместо того, чтобы последовательно удалять каждый элемент.
  • Vector* v = Vector[100]; просто не будет компилироваться. Напишите Vector v[100]; и он выделит массив векторов в стеке. Вы не можете удалить его вручную.
  • x, y, z находятся в куче, поскольку весь объект находится в куче
  • items[10] также выделяется в куче, так как она составляет часть объекта. Чтобы удалить его, просто вызовите delete v2;. Вам не нужен специальный деструктор, если вы не выделяете ничего в конструкторе.
  • int* items; хранится в стеке как часть объекта, выделенного в стеке. Вам не нужно удалять его, он автоматически удаляется при выходе из области действия.