使用常量值直接初始化数组
每当您在 C# 中分配一个新数组时,
new T[length]
数组条目都会设置为默认值 T。如果 T
是引用类型或 T 的结果,则为 null
如果 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# 数组初始化 - 使用非默认值,使用 < code>Enumerable.Repeat(value, length).ToArray() 不是选项,因为 Enumerable.ToArray
分配一个新数组,然后将值复制到其中。
Whenever you allocate a new array in C# with
new T[length]
the array entries are set to the default of T. That is null
for the case that T
is a reference type or the result of the default constructor of T
, if T
is a value type.
In my case i want to initialize an Int32
array with the value -1:
var myArray = new int[100];
for (int i=0; i<myArray.Length; i++) { myArray[i] = -1; }
So after the memory is reserved for the array, the CLR loops over the newly allocated memory and sets all entries to default(int) = 0. After that, my code sets all entries to -1.
That makes the initialization redundant. Does the JIT detect this and neglects the initialization to 0 and if not, is there a way to directly initialize a portion of memory with a custom value?
Referring to C# Array initialization - with non-default value , using Enumerable.Repeat(value, length).ToArray()
is no option, because Enumerable.ToArray
allocates a new array and copies the values to it afterwards.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
如果您购买被认为有些有害的数组,那么你的问题将毫无意义,因为你会写:
If you buy into Arrays considered somewhat harmful, then your question would be moot as you would write:
我非常怀疑 JIT 是否会优化掉这种情况下的默认设置。 原因是这将是一个可观察到的差异。 考虑以下稍微改变的场景。
循环完全有可能抛出。 至少,JIT 可能无法证明事实并非如此。 如果它确实抛出并且 CLR 没有默认初始化内存,并且您仍然拥有对 obj 的引用,则结果将是可见的。
I highly doubt that the JIT will optimize away the default set for this scenario. The reason being is that this would be an observable difference. Consider the following slightly altered scenario.
It's entirely possible for the loop to throw. At least, it's probably not possible for the JIT to prove it doesn't. If it did throw and the CLR did not default initialize the memory, the result would be observable if you still had a reference to obj.
我建议使用 Array.Fill 作为用初始值填充数组的一种非常简洁的方法:
这会将
isPrime
数组中的所有值初始化为true
。I suggest using
Array.Fill
as a very succint way to fill an array with an initial value:This initializes all values in the
isPrime
array totrue
.如果您正在寻找一种内衬解决方案,那么您可以使用以下产品:
If you are looking for one liner solution then you could use below:
与 Dan 的答案类似,但不需要使用集合:
Similar to Dan's answer but without the need of using collections:
这并不多余。
假设在初始化循环期间抛出异常。 如果 CLR 没有首先清除内存,您可能能够“看到”原始未初始化的内存,这是一个非常糟糕的主意,特别是从安全角度来看。 这就是 CLR 保证将任何新分配的内存擦除为 0 位模式的原因。
顺便说一句,同样的论点也适用于对象中的字段。
我想在这两种情况下,CLR 都可以检查在完成初始化之前您不会使数组在其他地方可见,但这是一个复杂的检查,以避免非常简单的“擦除该内存区域”。
It's not redundant.
Suppose an exception is thrown during your initialization loop. If the CLR hasn't cleared the memory first, you might be able to "see" the original uninitialized memory, which is a very bad idea, particularly from a security standpoint. That's why the CLR guarantees that any newly allocated memory is wiped to a 0 bit pattern.
The same argument holds for fields in an object, by the way.
I suppose in both cases the CLR could check that you're not going to make the array visible elsewhere before finishing initialization, but it's a complicated check to avoid a pretty simple "wipe this area of memory".