新的总是在C++/C#/ Java中分配在堆上

Ale*_*lex 13 c# c++ java memory memory-management

无论使用C++或C#还是Java,我的理解始终是当我们使用new关键字创建对象时,它会在堆上分配内存.我认为new只需要引用类型(类),并且原始类型(int,bool,float等)永远不会使用new并且总是在堆栈上(除非它们是实例化的类的成员变量)与new).不过,我一直在阅读信息,这让我怀疑这个长期存在的假设,至少对于Java和C#.

例如,我刚注意到在C#中,new运算符可用于初始化值类型,请参见此处.这是规则的一个例外,该语言的辅助功能,如果是,那么还会有哪些其他例外?

有人可以澄清一下吗?

fre*_*low 25

我认为只有引用类型(类)需要new,而原始类型(int,bool,float等)从不使用new

在C++中,如果要执行以下操作,可以在堆上分配基元类型:

int* p = new int(42);
Run Code Online (Sandbox Code Playgroud)

如果你想要一个共享计数器,这很有用,例如在实现中shared_ptr<T>.

此外,您不必在C++中使用new with class:

void function()
{
    MyClass myObject(1, 2, 3);
}
Run Code Online (Sandbox Code Playgroud)

这将myObject在堆栈上分配.请注意,new在现代C++中很少使用.

此外,您可以operator new在C++中重载(全局或特定于类),因此即使您说new MyClass,该对象也不一定在堆上分配.

  • 好吧,`new`在C++中有许多不同的用法...而不是`new char [n]`,你使用`std :: string`.而不是`new MyClass [n]`,你使用`std :: vector <MyClass>`.如果你想共享对象,而不是`MyClass*p = new MyClass`,你可以使用`auto p = make_shared <Class>()`等. (8认同)
  • 谢谢.在现代c ++中使用了什么而不是new? (5认同)
  • @Deqing 为什么?我们有 `make_shared` 和 `make_unique`。 (2认同)

Ale*_* C. 8

我不确切地知道Java(并且很难获得有关它的文档).

在C#中,new调用构造函数并返回一个新对象.如果它是值类型,则在堆栈(例如,局部变量)或堆上分配(例如,盒装对象,引用类型对象的成员).如果它是引用类型,它总是在堆上并由垃圾收集器管理.有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/fa0ab757(v=vs.80).aspx.

在C++中,"新表达式"返回指向具有动态存储持续时间的对象的指针(即,您必须自行销毁).在C++标准中没有提到堆(具有这种意义),并且获得这种对象的机制是实现定义的.

  • 在c#中,"new"总是返回对堆上对象的引用,而不是与GC绑定 (3认同)
  • 令人讨厌的是,虽然你*可以*在 C# 中说 `int i = new int()`,你不能说 `new int(1)`——这是一种让我感到困惑的贫血伪结构,我来自C++...我目前正试图进入 C#,但这些事情让我觉得没有经过深思熟虑。 (2认同)

sta*_*ica 7

无论使用C++或C#还是Java,我的理解始终是当我们使用new关键字创建对象时,它会在堆上分配内存.

您的理解不正确:

  • new可能在不同的编程语言中有不同的工作方式,即使这些语言在表面上相似也是如此.不要让C#,C++和Java的类似语法误导你!

  • 术语"堆"和"堆栈"(因为它们在内部存储器管理的上下文中被理解)与所有编程语言无关.可以说,这两个概念更多的是实现细节,而不是它们是编程语言官方规范的一部分.

    (IIRC,至少C#和C++都是如此.我不了解Java.)

    事实上,它们是如此广泛的实施细节并不意味着你应该依靠这种区别,也不应该知道它!(但是,我承认我通常发现在内部了解"事情如何运作"是有益的.)

我建议你不要过于担心这些概念.你需要做的正确的重要事情是理解语言的语义; 例如,对于C#或任何其他.NET语言,引用和值类型语义的差异.

示例:C#规范关于运算符的内容new:

请注意ECMA(第4版)发布C#规范的以下部分未提及任何"堆栈"或"堆":

14.5.10新运营商

new运算符用于创建类型的新实例.[...]

new运算符意味着创建类型的实例,但不一定意味着动态分配内存.特别是,值类型的实例不需要超出它们所在的变量的额外内存,并且当new用于创建值类型的实例时,不会发生动态分配.

相反,它谈到"动态分配内存",但这不是一回事:你可以动态地在堆栈上,堆上或其他任何地方(例如在硬盘驱动器上)分配内存.

什么是说的,但是,是值类型的实例存储在原处,这正是价值型语义是一回事:值类型实例分配过程中被复制,而引用类型实例引用/"别名".是重要的事情要理解,而不是"堆"或"堆栈"!

  • 请向在C#中问我堆与堆栈问题的采访者建议这个:) (4认同)