【问题标题】:Direct array initialization with a constant value使用常量值直接初始化数组
【发布时间】:2010-10-13 12:35:59
【问题描述】:

每当您在 C# 中使用

分配一个新数组时
new T[length]

数组条目设置为默认的T。即null,如果T是引用类型或T的默认构造函数的结果,如果T是值类型.

在我的例子中,我想用值 -1 初始化一个 Int32 数组:

var myArray = new int[100];
for (int i=0; i<myArray.Length; i++) { myArray[i] = -1; }

因此,在为数组保留内存之后,CLR 循环遍历新分配的内存并将所有条目设置为 default(int) = 0。之后,我的代码将所有条目设置为 -1。

这使得初始化变得多余。 JIT 是否检测到这一点并忽略初始化为 0,如果没有,有没有办法直接用自定义值初始化一部分内存?

引用C# Array initialization - with non-default value ,使用Enumerable.Repeat(value, length).ToArray() 是不行的,因为Enumerable.ToArray 分配一个新数组,然后将值复制到它。

【问题讨论】:

  • 如果你有字节数组,那么P/Invoke could help。但是,如果数组元素大小大于字节(如您的情况) - 此方法将无济于事。

标签: c# arrays initialization constants


【解决方案1】:

类似于 Dan 的回答,但不需要使用集合:

int[] myArray = Enumerable.Repeat(-1, 100).ToArray();

【讨论】:

    【解决方案2】:

    这不是多余的。

    假设在您的初始化循环期间引发了异常。如果 CLR 没有首先清除内存,您可能能够“看到”原始未初始化的内存,这是一个非常糟糕的主意,特别是从安全角度来看。这就是 CLR 保证任何新分配的内存都被擦除为 0 位模式的原因。

    顺便说一句,同样的论点也适用于对象中的字段。

    我想在这两种情况下,CLR 都可以在完成初始化之前检查你不会让数组在其他地方可见,但这是一项复杂的检查,以避免非常简单的“擦除该内存区域”。

    【讨论】:

    • 我看不出哪里会抛出异常。 JIT 足够智能,可以在循环中禁用对数组的范围检查,因此它也可以检测到不会发生异常。
    【解决方案3】:

    如果您购买Arrays considered somewhat harmful,那么您的问题将没有实际意义:

    var myArray = new List<int>(Enumerable.Repeat(-1, 100));
    

    【讨论】:

    • 可能值得一提的是,他的链接是 Eric Lippert 的博客,这表明数组是坏消息,因为在许多情况下,“调用者正在请求值。被调用者通过返回变量来满足请求。” Lippert 然后有趣地争辩说,由于物理限制使处理器更快,“我们将需要允许普通人编写可并行到多核 [and that] 数组的代码的编程语言......强烈反对这个目标。 "这是一本很好的读物,即使与这个问题几乎没有切线相关。 ;^)
    • 数组是一个和其他工具一样的工具。如果您正在编写需要使用数字索引访问值的性能关键代码,那么数组性能根本无法被击败,即使是列表也不行(它不是一百万英里,但数组仍然更快,如果您'正在处理大量数据,这很重要)。这完全取决于您的用例并做出适当的权衡。老实说,我已经厌倦了“X 被认为有害”的比喻,因为它通常是根据过于狭窄的 PoV 编写的。
    【解决方案4】:

    我非常怀疑 JIT 是否会针对这种情况优化默认设置。原因是这将是一个可观察到的差异。考虑以下稍微改变的场景。

    obj.myArray = new int[100];
    for (int i=0; i<myArray.Length; i++) { obj.myArray[i] = -1; }
    

    循环完全有可能抛出。至少,JIT 可能无法证明它不是。如果它确实抛出并且 CLR 没有默认初始化内存,那么如果您仍然有对 obj 的引用,则结果将是可观察的。

    【讨论】:

    • 将问题限制在局部变量上。
    • @Rauhotz,此时您必须开始质疑优化是否值得。您现在已将其限制在非常受限的场景中。
    【解决方案5】:

    我建议使用Array.Fill 作为一种非常简洁的方式来用初始值填充数组:

    bool[] isPrime = new bool[MaxNum];
    Array.Fill(isPrime, true);
    

    这会将isPrime 数组中的所有值初始化为true

    【讨论】:

    【解决方案6】:

    如果您正在寻找一种衬垫解决方案,那么您可以使用以下方法:

    var myArray = Array.ConvertAll(new int[100], i => -1);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-08
      • 1970-01-01
      • 1970-01-01
      • 2016-10-28
      • 2019-06-24
      • 1970-01-01
      • 2015-09-10
      • 2018-07-15
      相关资源
      最近更新 更多