Создание объектов С++

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

BTree *btree = new BTree;

и

BTree btree;

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

Какой способ лучше, и какая разница?

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

Ответ 1

Две отличия:

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

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

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

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

Ответ 2

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

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

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

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

Ответ 3

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

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

// 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 разрешено в последних спецификациях языка, вторая причина является ключом к этой проблеме.

Ответ 4

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

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

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

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

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

Ответ 5

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

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

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

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

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

Ответ 6

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

Здесь хорошо читайте. Куча и стопка