Всегда ли новый размещать в куче в C ++ / C # / Java - PullRequest
13 голосов
/ 07 августа 2011

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

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

Может кто-нибудь объяснить это?

Ответы [ 9 ]

25 голосов
/ 07 августа 2011

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

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

int* p = new int(42);

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

Также выВы не обязаны использовать new с классами в C ++:

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

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

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

8 голосов
/ 07 августа 2011

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

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

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

7 голосов
/ 07 августа 2011

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

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

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

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

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

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

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

Пример: что спецификация C # говорит об операторе new:

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

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

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

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

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

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

3 голосов
/ 07 августа 2011

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

  • переменные (кроме блоков захвата и блоков итераторов) и поля в структуре, которая сама в стеке, живут в стеке
  • захватывает, блоки итераторов, поля чего-либо, находящегося в куче, и значения в массиве живут в куче, как и «коробочные» значения
2 голосов
/ 07 августа 2011

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

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

2 голосов
/ 07 августа 2011

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

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

2 голосов
/ 07 августа 2011

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

Integer n = new Integer(2);

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

0 голосов
/ 07 августа 2011

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

См. Какая польза от "размещения новых"?

0 голосов
/ 07 августа 2011

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

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