困境使用值类型和`new`运营商在C# [英] Dilemma with using value types with `new` operator in C#

查看:111
本文介绍了困境使用值类型和`new`运营商在C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

运算符new()用于参考类型,实例空间是在堆上分配和参考变量本身放置在堆栈中。除此之外,引用类型,也就是在堆上分配,该实例中的一切都归零了。
例如这里是一个类:

When operator new() is used with reference type, space for the instance is allocated on the heap and reference variable itself is placed on the stack. Besides that, everything within the instance of reference type, that is allocated on the heap, is zeroed-out.
For example here is a class:

class Person
{
    public int id;
    public string name;
}

在以下code:

class PersonDemo
{
    static void Main()
    {
        Person p = new Person();
        Console.WriteLine("id: {0}  name: {1}", p.id, p.name);
    }
}

P 变量是在栈上和(所有的承包商,​​客人)的创建的实例是在堆。 p.id 0 p.name 会为。 这将是这种情况,因为在堆上分配的一切都归零了。

p variable is on the stack and the created instance of Person (all of its memebers) is on the heap. p.id would be 0 and p.name would be null. This would be the case because everything allocated on the heap is zeroed-out.

现在,如果我用用运营商值类型是什么我感到困惑的是。例如,考虑到以下考虑结构:

Now what I'm confused about is if I'm using a value type with new operator. For example, take into consideration following structure:

struct Date
{
    public int year;
    public int month;
    public int day;
}

class DateDemo
{
    static void Main()
    {
        Date someDate;
        someDate= new Date();

        Console.WriteLine("someDate is: {0}/{1}/{2}", 
            someDate.month, someDate.day, someDate.year);
    }
}

现在我想知道是什么做的,从主要做了以下几行:

Now I would like to know what do the following lines from main do:

        Date someDate;
        someDate= new Date();

在第一行 someDate 变量被分配在堆栈中。 precisely 12个字节。
 我的提问在第二行发生了什么?这是什么运算符new()吗?难道它只是零出日期成员结构或者它分配的堆空间呢?一方面我不希望来,因为在第一线的内存分配的堆空间,当然是已经分配的堆栈结构实例上。在另一方面,我希望分配在堆上的空间,并返回该空间的地址,因为这是应该做的。 也许这是因为我从C ++背景的。

In first line someDate variable is allocated on the stack. Precisely 12 bytes.
My question is what happens on the second line? What does operator new() do? Does it only zero-out members of Date structure or it allocates space on the heap as well? On one side I wouldn't expect new to allocate space on the heap, of course because in the first line memory is already allocated on the stack for the structure instance. On the other hand, I would expect new to allocate space on the heap and return address of that space, because that's what new should do. Maybe this is because I'm coming from C++ background.

不过如果回答是:当使用值类型,它只是零出对象的成员,比它是有点不一致的含义运算符,因为:

Nevertheless if the answer is: "when new is used with value types, it only zeroes-out members of object", than it's a bit inconsistent meaning of new operator because:

  1. 在使用值类型,对象的堆栈上,只零出成员
  2. 在使用引用类型,它在堆上的实例,并zerous出它的成员
  3. 分配内存
  1. when using new with value types, it only zeroes-out members of object on the stack
  2. when using new with reference types, it allocates memory on the heap for the instance and zerous-out it's members

在前进,
谢谢 干杯

Thanks in advance,
Cheers

推荐答案

首先请允许我纠正你的错误。

First let me correct your errors.

当运算符new()用于引用类型,为实例空间被分配在堆上和参考变​​量本身放置在堆栈中。

When operator new() is used with reference type, space for the instance is allocated on the heap and reference variable itself is placed on the stack.

这是新的结果的引用是一个的的,不是的变量的。该值的引用的存储位置。

The reference that is the result of "new" is a value, not a variable. The value refers to a storage location.

的参考,当然是回的在CPU寄存器的。是否该CPU寄存器的内容是不断复制到调用堆栈为抖动的优化决定的事项。它不需要再多活在堆栈上;它可以永远活在寄存器中,也可以直接复制从注册到托管堆上,或在不安全code,它可以直接复制到非托管内存。

The reference is of course returned in a CPU register. Whether the contents of that CPU register are ever copied to the call stack is a matter for the jitter's optimizer to decide. It need not ever live on the stack; it could live forever in registers, or it could be copied directly from the register to the managed heap, or, in unsafe code, it could be copied directly to unmanaged memory.

该协议栈是一个实现细节。你不的知道的时候,堆,除非你看看即时编译code被使用。

The stack is an implementation detail. You don't know when the stack is being used unless you look at the jitted code.

p变量是堆栈和Person(所有的承包商,​​客人)的创建的实例就在堆上。 p.id是0和p.name将是空的。

p variable is on the stack and the created instance of Person (all of its memebers) is on the heap. p.id would be 0 and p.name would be null.

正确,尽管当然再次p可以被实现为一个寄存器,如果抖动如此决定。它不需要使用堆叠,如果有可用的寄存器。

Correct, though of course again p could be realized as a register if the jitter so decides. It need not use the stack if there are available registers.

您好像pretty的挂了这个想法堆栈正在使用。抖动可能有大量的寄存器供其使用,而这些寄存器可以是pretty的大。

You seem pretty hung up on this idea that the stack is being used. The jitter might have a large number of registers at its disposal, and those registers can be pretty big.

我从C ++背景的。

嗯,这解释了为什么你就这么挂了这个堆栈VS堆东西。学习不再担心了。我们设计的东西在哪里居住,只要他们需要一个托管内存环境。是否经理选择使用栈,堆或寄存器来有效地管理存储器高达它

Ah, that explains why you're so hung up on this stack vs heap thing. Learn to stop worrying about it. We've designed a managed memory environment where things live as long as they need to. Whether the manager chooses to use stack, heap or registers to efficiently manage the memory is up to it.

在第一行someDate变量被分配在堆栈中。 precisely 12个字节。

In first line someDate variable is allocated on the stack. Precisely 12 bytes.

让我们假设为参数的缘故,这12字节结构被分配在堆栈中。似乎是合理的。

Let's suppose for the sake of argument that this 12 byte structure is allocated on the stack. Seems reasonable.

我的问题是在第二行发生了什么?什么是运营商新的()呢?难道它只是零淘汰日期结构的成员,或者分配空间堆呢?

My question is what happens on the second line? What does operator new() do? Does it only zero-out members of Date structure or it allocates space on the heap as well?

现在的问题presupposes一个错误的二分法,因此不可能回答的说明。现在的问题presents上任意两个,或替代品,两者都不是一定正确。

The question presupposes a false dichotomy and is therefore impossible to answer as stated. The question presents two either-or alternatives, neither of which is necessarily correct.

在一边,我不会期待新的分配过程中的空间堆上,因为在第一线记录被分配在堆栈的结构实例上。

On one side I wouldn't expect new to allocate space on the heap, of course because in the first line memory is already allocated on the stack for the structure instance.

正确的结论,似是而非的推理。没有堆分配进行的因为编译器知道这个操作的任何部分,需要一个长期存在的存储的。这就是堆是什么;当编译器确定给定的变量可能活得比目前的方法激活,它会产生code的分配存储上的长住堆存储的变量。如果确定变量绝对具有短的寿命,然后它使用的栈(或寄存器),作为优化

Correct conclusion, specious reasoning. No heap allocation is performed because the compiler knows that no part of this operation requires a long-lived storage. That's what the heap is for; when the compiler determines that a given variable might live longer than the current method activation, it generates code which allocates the storage for that variable on the long-lived "heap" storage. If it determines that the variable definitely has a short lifetime then it uses the stack (or registers), as an optimization.

在另一方面,我希望新的分配空间在堆上并返回该空间的地址,因为这是新的应该做的。

On the other hand, I would expect new to allocate space on the heap and return address of that space, because that's what new should do.

不正确的。 新并不保证堆分配。相反,新保证一个构造函数被调用的置零的记忆。

Incorrect. "new" does not guarantee that heap is allocated. Rather, "new" guarantees that a constructor is called on zeroed-out memory.

让我们回到你的问题:

难道它只是零淘汰日期结构的成员,或者分配空间堆呢?

Does it only zero-out members of Date structure or it allocates space on the heap as well?

我们知道它不会在堆中分配空间。是否零出之日起结构的成员?

We know it does not allocate space on the heap. Does it zero out members of the date structure?

这是一个复杂的问题。该规范说,当你说

That's a complicated question. The specification says that what happens when you say

someDate = new Date();    

  • someDate的地址被确定
  • 在空间分配(关堆栈)为新对象。它被清零。
  • 则构造函数,如果有的话,被称为与本是一个参照新的堆栈存储器
  • 然后新堆栈存储的字节拷贝到someDate的地址。
    • the address of someDate is determined
    • space is allocated (off "the stack") for the new object. It is zeroed out.
    • then the constructor, if any, is called, with "this" being a reference to the new stack storage
    • then the bytes of the new stack storage are copied to the address of someDate.
    • 现在,是实际发生的事情的?你会完全在您的权利,请注意,这是的无法分辨的新的堆栈空间是否被分配,初始化和复制,或旧的堆栈空间是否被初始化。

      Now, is that actually what happens? You would be perfectly within your rights to notice that it is impossible to tell whether new stack space is allocated, initialized and copied, or whether the "old" stack space is initialized.

      答案是的情​​况下,编译器推断,这是不可能的用户,以通知该现有栈空间被突变,现有栈空间被突变和额外的分配和随后的复制是消隐

      在的情况下,编译器是无法推断出,然后一个临时堆栈槽被创建,初始化为零,建造,由构造突变,然后将所得的值被复制到变量。 这可以确保如果构造函数抛出异常,则无法观察到不一致的状态变量。

      In cases where the compiler is unable to deduce that, then a temporary stack slot is created, initialized to zeros, constructed, mutated by the constructor, and then the resulting value is copied to the variable. This ensures that if the constructor throws an exception, you cannot observe an inconsistent state in the variable.

      有关这个问题,编译器的分析更详细信息,请参见关于这个问题我的文章。

      For more details about this issue and its analysis by the compiler see my article on the subject.

      <一个href="http://blogs.msdn.com/b/ericlippert/archive/2010/10/11/debunking-another-myth-about-value-types.aspx">http://blogs.msdn.com/b/ericlippert/archive/2010/10/11/debunking-another-myth-about-value-types.aspx

      这篇关于困境使用值类型和`new`运营商在C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆