价值类型的分配
本文关键字:分配 类型 | 更新日期: 2023-09-27 17:57:48
当您将一个值类型的实例分配给另一个实例时,对象会被逐位复制到目标位置:
private struct Word
{
public Word(char c) { ... }
}
public void Method(Word a)
{
Word b = a; //a is copied and stored in b
}
但给定以下代码:
private Word _word;
public void Method() {
_word = new Word('x');
}
我怀疑首先计算右侧(RHS)表达式(它实例化堆栈上的值类型),然后,将值复制并存储在堆上_word
字段的位置。
另一种选择是考虑左侧,直接在_word
上实例化值类型,避免复制对象。
我的怀疑正确吗?如果是这样的话,我想可以肯定地假设第一块代码的性能会比第二块好。
//1 instantiation + 10k copies
Word[] words = new Word[10000];
Word word = new Word('x');
for (int i = 0; i < 10000; i++)
words[i] = word;
//10k instantiations + 10k copies
Word[] words = new Word[10000];
for (int i = 0; i < 10000; i++)
words[i] = new Word('x');
注意:我并没有试图对任何东西进行微观优化。
编辑:正如Lee所说,我问题的核心是:结构是直接分配到位的,还是需要分配然后复制?
当您将一个值类型的实例分配给另一个实例时,对象会被逐位复制到目标位置
将值类型的实例分配给同一类型的变量时,值将复制到目标位置,是的。但引用类型也是如此:引用被逐位复制到目标位置。引用当然会保持原样。
我怀疑右侧(RHS)表达式是首先评估的
规范规定,对左手边进行求值以生成变量,然后对右手边进行求值来生成值,然后进行赋值。
在你给出的例子中,左手边的评估不会产生可观察到的副作用,因此它的评估可以由C#编译器中的优化器、抖动或CPU(如果他们中的任何一个选择的话)重新排序。但如果你有类似的东西
x[i++] = v();
则左手侧的副作用必须在右手侧的呼叫之前发生。
我问题的核心是:结构是直接分配到位的,还是需要分配然后复制?
规范规定,结构被分配在一个临时位置——在实践中通常是堆栈或寄存器——然后复制到它们的最终目的地。然而,在某些情况下,优化器可以确定用户不可能注意到突变是否在最终目的地"原位"发生。这是一个复制省略优化,如果C#编译器认为可以逃脱惩罚,它将执行此优化。
有关更多详细信息,请参阅我关于主题的文章:
http://ericlippert.com/2010/10/11/debunking-another-myth-about-value-types/
两者都是首选吗?
多个相同结构的业务案例是什么
如果你需要多个相同的对象,一个结构是最好的选择吗?
以这种方式初始化的结构可能不是示例用例的好解决方案
在新数组中,WordStruct使用默认的ctor(无ctor)进行分配和初始化
您没有用另一个ctor初始化结构数组的选项
如果你确实需要相同的结构,那么这将是首选的
WordStruct[] WordStructS = new WordStruct[1000];
for (int i = 0; i < WordStructS.Length; i++) { WordStructS[i].C = 'x'; }
如果你真正需要做的是多个相同的对象,那么考虑一个类
类新数组已分配但尚未初始化
使用默认构造函数初始化不会浪费资源
WordClass[] WordClassS = new WordClass[1000];
for (int i = 0; i < WordClassS.Length; i++) { WordClassS[i] = new WordClass('x'); }
如果您想泛化对象(结构或类)的深层副本,请考虑IConable
在结构的情况下,我怀疑它比逐位复制更有效(但我不是肯定的)
在类的情况下,它将使克隆(深度复制)而不是引用
public struct WordStruct : ICloneable
{
public char C;
public WordStruct(char C)
{
this.C = C;
}
public object Clone()
{
WordStruct newWordStruct = (WordStruct)this.MemberwiseClone();
return newWordStruct;
}
}
我知道你在评论中说了好奇,但这在问题中并不清楚
在这个问题中,你说第一块代码比第二块更可取
我知道这是一个有趣的好奇心问题
但如果只是好奇,那么问题应该停止在
我的怀疑正确吗?