由于引入了C#7.0的引用返回功能,并且基于我的理解,这样的功能需要在编译器上进行一些重新布线才能将此引用仅存储在堆上的变量上,是否可以存储返回对堆栈变量的引用,或新的ref声明是否确保变量始终存储在堆上?
ref int x = ref DoSomething(data);
// Is the value of x now on the stack or the heap? Or is x stored on the stack as a reference and the value on the heap?
我的理解基于this article:
最后,CLR确实允许“ref return types”;你理论上可以 有一个方法“ref int M(){...}”返回对a的引用 整数变量。如果出于某种奇怪的原因我们决定允许 在C#中,我们必须修复编译器和验证程序以便它们 确保只能将refs返回到变量 众所周知,它们在堆上,或者已知在堆栈上“降低” 而不是被叫者。
答案 0 :(得分:10)
这首歌的名字叫做#34; Haddocks'眼睛"' 噢,这就是这首歌的名字,是吗?'爱丽丝说,试着感兴趣。 “不,你不明白,'骑士说,看起来有点烦恼。 '这叫什么名字。这个名字真的是"老年人"。' '然后我应该说'#34;这就是这首歌的名字"?'爱丽丝纠正自己。 “不,你不应该:那是另一回事!这首歌被称为" Ways and Means":但这只是它所称的,你知道!' 嗯,这首歌是什么?'爱丽丝说,他此时已经完全不知所措了。 '我来了,'骑士说。 '这首歌真的是" A-sitting on a Gate":而且曲调是我自己的发明。'
这首歌,这首歌的名字,这个名字叫什么,这首歌的名字显然都是不同的。
有三件事你不能混淆:
ref int x = ref DoSomething(data);
x的值现在是堆栈还是堆?
表达式x
是另一个变量的别名。
该变量具有值。
假设别名变量是值类型。是别名变量,因此它的值是临时池(又名" stack")还是长期池("堆")?我们不知道。我们也不关心。我们知道无论哪个,我们都保证这个变量现在还活着。
但是我们可以猜测:ref返回的变量通常是别名到堆分配的变量,因为我们确定它们还活着。
假设别名变量属于引用类型。 引用是存储在堆栈还是堆上?同样,我们也不知道,出于同样的原因。 是堆栈或堆上的引用的引用对象吗?它可以在堆上,也可以为null;我们 保证。
或者x是否存储在堆栈上作为引用和堆上的值?
x
是指 x
别名的变量,还是指本地x
本身?本地本身存储在堆栈或寄存器中;它永远不会被提升到封闭类的领域。变量别名可能在任何地方,但如上所述,很可能在堆上。
答案 1 :(得分:7)
ref int x
是int* x
的语法糖,是变量在运行时的行为方式。将变量作为参数传递给方法并且参数声明为ref
时,您获得的行为完全相同,调用者传递指向变量的指针。指针不关心值的存储位置,实际上可以存储在任何地方。请注意,您无法传递属性,它没有存储空间。
他们在C#v7中必须做的非常重要的事情是确保你不会意外地创建dangling pointer bug。在C和C ++等语言中臭名昭着,在这些语言中它是未定义的行为,不需要编译器生成诊断。很多带有该bug的程序似乎运行得很好,直到程序中看似微不足道的变化(添加函数调用)破坏了指向的值。
实际上并不难做afaik,被调用方法的局部变量是麻烦制造者。方法返回后它们不再存在,因此引用变为无效。在C#v7中将给出编译错误的特定方案。但是如果局部变量是调用者之一,那么它很好,并且它通过参数传入引用,该变量仍然存活。