Новые всегда выделяются в куче в С++/С#/Java

Мое понимание всегда было, независимо от С++ или С# или Java, что, когда мы используем ключевое слово new для создания объекта, оно выделяет память в куче. Я думал, что new нужен только для ссылочных типов (классов), и что примитивные типы (int, bool, float и т.д.) Никогда не используют new и всегда идут в стек (кроме случаев, когда они являются переменной-членом класса, который создается с помощью new). Тем не менее, я читал информацию, что заставляет меня сомневаться в этом долговременном предположении, по крайней мере, для Java и С#.

Например, я только заметил, что в С# оператор new может использоваться для инициализации типа значения, см. здесь. Является ли это исключением из правила, вспомогательной особенностью языка, и если да, то какие другие исключения будут?

Кто-нибудь может прояснить это?

Ответ 1

Я думал, что новое необходимо только для ссылочных типов (классов), и что примитивные типы (int, bool, float и т.д.) никогда не будут использовать новые

В С++ вы можете выделить примитивные типы в куче, если хотите:

int* p = new int(42);

Это полезно, если вы хотите использовать общий счетчик, например, при реализации shared_ptr<T>.

Кроме того, вы не вынуждены использовать новые с классами в С++:

void function()
{
    MyClass myObject(1, 2, 3);
}

Это будет выделять myObject в стеке. Обратите внимание, что new редко используется в современном С++.

Кроме того, вы можете перегружать operator new (как глобально, так и специфично для класса) на С++, поэтому, даже если вы скажете new MyClass, объект не обязательно получает выделение в куче.

Ответ 2

Я не знаю точно о Java (и, похоже, довольно сложно получить документацию об этом).

В С#, new вызывает конструктор и возвращает новый объект. Если он имеет тип значения, он выделяется в стеке (например, локальная переменная) или в куче (например, в штучной упаковке объект, объект объекта ссылочного типа). Если он имеет ссылочный тип, он всегда переходит в кучу и управляется сборщиком мусора. Подробнее см. http://msdn.microsoft.com/en-us/library/fa0ab757(v=vs.80).aspx.

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

Ответ 3

Мое понимание всегда было, независимо от С++ или С# или Java, что, когда мы используем ключевое слово new для создания объекта, оно выделяет память в куче.

Ваше понимание неверно:

  • new может работать по-разному на разных языках программирования, даже если эти языки поверхностно похожи. Не позволяйте подобному синтаксису С#, С++ и Java вводить вас в заблуждение!

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

    (IIRC, это верно, по крайней мере, для С# и С++. Я не знаю о Java.)

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

Я бы предположил, что вы перестаете слишком беспокоиться об этих концепциях. Важная вещь, которую вам нужно получить, это понять семантику языка; например, для С# или любого другого языка .NET, разница в семантике ссылки и значения.

Пример. Что спецификация С# говорит о операторе new:

Обратите внимание, что в следующей части спецификации С#, опубликованной ECMA (4-е издание), не упоминается ни один "стек "или" куча":

14.5.10 Новый оператор

Новый оператор используется для создания новых экземпляров типов. [& Hellip;]

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

Вместо этого он говорит о "динамическом распределении памяти", но это не одно и то же: вы можете динамически распределять память в стеке, в куче или в другом месте (например, на жестком диске), если на то пошло.

Однако он говорит о том, что экземпляры типов значений сохраняются на месте, что и есть то, что означает семантика типа значения: экземпляры типа значения копируются во время назначения, в то время как ссылочные типы экземпляров ссылаются/алиас ". Это важно понять, а не" кучу" или "стек"!

Ответ 4

В С#, a class всегда живет в куче. A struct может быть либо в куче, либо в стеке:

  • (кроме блоков захвата и итератора) и полей в структуре, которая сама находится в стеке, находящейся в стеке
  • захватывает, блокирует итераторы, поля чего-то, находящегося в куче, и значения в массиве, находящиеся в куче, как и значения "в штучной упаковке"

Ответ 5

(Обращение к Java). Вы сказали, что правильные примитивы выделены в стеке (есть исключения, например, закрытие). Однако вы можете ссылаться на такие объекты, как:

Integer n = new Integer(2);

Это относится к объекту Integer, а не к примитивному int. Возможно, это был ваш источник замешательства? В этом случае n будет выделено в куче. Возможно, ваше замешательство было вызвано autoboxing правилами? Также см. этот вопрос для получения дополнительной информации об автобоксинге. Ознакомьтесь с комментариями к этому ответу для исключений из правила, в котором в куче выделены примитивы.

Ответ 6

Что касается С#, прочитайте Истина о типах значений. Вы увидите, что типы значений могут также находиться в куче.

И по этому вопросу предлагается указать ссылочные типы в стек. (но это не происходит в данный момент)

Ответ 7

Java 7 не выполняет анализ, чтобы определить, может ли объект быть выделен в стеке, в соответствии с http://download.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html.

Однако вы не можете указывать время выполнения для размещения объекта в куче или в стеке. Это делается автоматически.

Ответ 8

В Java и С# нам не нужно выделять примитивные типы в куче. Они могут быть выделены в стек (не для того, чтобы они были ограничены стеком). Принимая во внимание, что в С++ мы можем иметь как примитивные, так и пользовательские типы, которые должны быть распределены как в стеке, так и в куче.

Ответ 9

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

См. Что используется для "размещения нового" ?