Создание объектов C ++ - PullRequest
14 голосов
/ 02 мая 2010

Я заметил, что есть два способа создания объектов C ++:

BTree *btree = new BTree;

и

BTree btree;

Из того, что я могу сказать, единственное различие заключается в том, как осуществляется доступ к объектам класса (. Vs. -> оператор), и когда используется первый способ, частные целые числа инициализируются равными 0.

Какой путь лучше и в чем разница?

Как вы знаете, когда использовать тот или другой?

Ответы [ 6 ]

32 голосов
/ 02 мая 2010

Два отличия:

  • они создают объекты в разных частях памяти (куча против стека)

  • Время жизни объекта отличается: В первом случае код управляет выделением памяти явно, , и он также должен явно управлять освобождением (используя delete / delete []).

    Во втором случае объект автоматически освобождается в конце его охватывающей области (либо метода, вложенного блока в методе, либо класса)

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

5 голосов
/ 02 мая 2010

Первая форма создает объект в куче, тогда как вторая создает его в стеке.

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

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

Если объект должен пережить функцию, лучше использовать новую форму.

3 голосов
/ 02 мая 2010

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

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

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

Срок службы памяти: Распределенная память кучи доступна за пределами функции распределения. Стек не является. Исходя из рассуждений о корректировке указателя стека, приведенного выше, после освобождения памяти она становится свободной и, скорее всего, будет перезаписана для следующего выделения стека.

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

3 голосов
/ 02 мая 2010

Другое различие между этими двумя формами - это время, когда для этих объектов выделяется память. Форма BTree bTree; называет статическое распределение, распределение которого выполняется во время компиляции - то есть компилятор организует пространство памяти для этого объекта в памяти при запуске. В то время как выделение для BTree *pbTree = new BTree, предполагаемое динамическое выделение - выполняется во время выполнения, т.е. память будет выделяться только тогда, когда запущенная программа достигнет этой точки.

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

// in this function, we want to return a copy of the parameter array
int *array_cpy( int *arr, int num ){
    int *copy = new int[ num ];

    int i;
    for( i = 0; i < num; i++ ){
        copy[ i ] = arr[ i ];
    }

    return copy;
}

Здесь определение int copy[ num ]; не подходит, одна из причин заключается в том, что я изложил выше, а другая - время жизни copy переживет функцию. Однако, учитывая, что VLA разрешено в недавней спецификации языка, вторая причина является ключевой для этой проблемы.

2 голосов
/ 02 мая 2010

Различие высокого уровня составляет время жизни объекта . Например, если вы пишете видеоигру, вы должны расположить объекты, соответствующие монстрам в куче, через new. Таким образом, лежащий в основе объект монстра живет ровно столько же, сколько и монстр, что непостижимо, когда вы пишете программу. Когда игрок убивает монстра, ваш код может уничтожить объект монстра, используя delete.

Счетчик общего счета, с другой стороны, вы бы использовали другую форму, потому что вы знаете, как долго вы хотите, чтобы счетчик оставался рядом (предположительно, до тех пор, пока игра запущена!). Поместив эту форму в «глобальную область» вне тела функции, она будет размещена статически как часть самого двоичного файла программы.

Наконец, если вы вычисляете сумму массива, например:

int mysum(int* arr, int len) {
  int sum = 0;
  for (int i = 0; i < len; ++i) { sum += arr[i] }
  return sum;
}

переменная sum размещена в стеке, что в принципе и является тем, что вам нужно: временная переменная, которую вам не нужно явно освобождать, и которая присутствует только тогда, когда эта функция действительно выполняется.

0 голосов
/ 02 мая 2010

Ну, они хранятся в совершенно разных областях памяти.

Вот хорошее чтение. Куча и стек

...