C# 价值类型的分配
将值类型的实例指定给另一个实例时,对象将逐位复制到目标位置:C# 价值类型的分配,c#,.net,clr,value-type,C#,.net,Clr,Value Type,将值类型的实例指定给另一个实例时,对象将逐位复制到目标位置: 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'); }
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)表达式,它实例化堆栈上的值类型,然后复制值并存储在堆上的\u word
字段的位置上
另一种方法是考虑左侧,直接在\u 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');
//1个实例化+10k个副本
单词[]单词=新词[10000];
单词=新词('x');
对于(int i=0;i<10000;i++)
单词[i]=单词;
//10k实例化+10k副本
单词[]单词=新词[10000];
对于(int i=0;i<10000;i++)
单词[i]=新词('x');
注意:我不是在尝试微优化任何东西
编辑:正如Lee所说,我的问题的核心是:结构是直接分配到位的,还是需要分配然后复制
将值类型的实例指定给另一个实例时,对象将逐位复制到目标位置
将值类型的实例指定给同一类型的变量时,该值将复制到目标位置,是。但引用类型也是如此:引用被逐位复制到目标位置。引用对象当然保持在它所在的位置
我怀疑首先计算右侧(RHS)表达式
规范规定,对左侧求值以生成变量,然后对右侧求值以生成值,然后进行赋值
在您给出的示例中,对左侧的评估不会产生明显的副作用,因此其评估可以由C#编译器中的优化器、jitter或CPU(如果其中任何一个选择)重新排序。但是如果你有
x[i++] = v();
然后左手边的副作用必须在右手边的呼叫之前发生
我的问题的核心是:结构是直接分配的,还是需要分配然后复制
该规范规定,结构被分配到一个临时位置——实际上通常是堆栈或寄存器——然后复制到它们的最终目的地。然而,在某些情况下,优化器可以确定用户不可能注意到突变是否发生在最终目的地。这是一个拷贝省略优化,如果C#编译器认为可以成功,它将执行此优化
有关更多详细信息,请参阅我的文章:
您喜欢哪一种 多个相同结构的业务案例是什么?
如果需要多个相同的对象,结构是最佳选择吗 以这种方式初始化的结构对于示例用例来说可能不是一个好的解决方案
在新数组中,使用默认的ctor(无ctor)分配和初始化WordStruct
您没有使用另一个ctor初始化结构数组的选项
如果您确实需要相同的结构,那么这将是首选
WordStruct[] WordStructS = new WordStruct[1000];
for (int i = 0; i < WordStructS.Length; i++) { WordStructS[i].C = 'x'; }
我知道你在评论中提到好奇,但这在问题中并不清楚在这个问题中,您声明第一块代码比第二块代码更可取 我知道这是一个有趣的好奇问题
但如果只是好奇,那么问题应该停在
我的怀疑正确吗?我想你是说最后一行是单词[I]=new Word()。答案可能很有趣,但我认为如果它能被优化,它会被优化。@WeylandYutani,谢谢;)如果您只是调用默认构造函数,那么可以完全删除循环,不是吗?结构已经初始化为零。@Lee是的,但这不是重点。这只是一个例子来说明我的意思。也许这是未指定的,因为您无法区分单线程执行下的区别。当然,如果ctor要执行副作用,那么您的两个代码片段就不相等了。感谢您的精彩解释,特别是博客文章,它解释了为什么结构被分配到临时位置(在大多数情况下)。那么,从我提供的两个代码示例来看,第一个更好,因为它可以避免在临时位置反复分配结构(假设没有副本省略),对吗?哦,当我说“首先计算RHS表达式”时,我的意思是:“RHS和LHS是独立评估的“。与中一样,LHS不会影响结构的分配,我现在知道这不一定是真的。@dcastro:C#编译器仅在目标为局部变量时省略副本;在您的示例中,目标是数组元素。第一个和第二个示例之间的真正节省可能不在于复制,而在于避免调用构造函数9999次。
WordClass[] WordClassS = new WordClass[1000];
for (int i = 0; i < WordClassS.Length; i++) { WordClassS[i] = new WordClass('x'); }
public struct WordStruct : ICloneable
{
public char C;
public WordStruct(char C)
{
this.C = C;
}
public object Clone()
{
WordStruct newWordStruct = (WordStruct)this.MemberwiseClone();
return newWordStruct;
}
}