C# 7.0 中通过引用返回的值是存储在堆栈中还是堆中?
Does the value returned by reference in C# 7.0 get stored on the stack or the heap?
自从引入 C# 7.0 的 return by reference 功能以来,根据我的理解,像这样的功能需要对编译器进行一些重新布线,以便仅将此引用存储在位于堆上的变量上, 是否可以在堆栈上存储对变量的 returned 引用,或者新的 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:
Finally, the CLR does allow “ref return types”; you could in theory
have a method “ref int M() { … }” that returned a reference to an
integer variable. If for some bizarre reason we ever decided to allow
that in C#, we’d have to fix up the compiler and verifier so that they
ensured that it was only possible to return refs to variables that
were known to be on the heap, or known to be “lower down” on the stack
than the callee.
The name of the song is called "Haddocks' Eyes".'
'Oh, that's the name of the song, is it?' Alice said, trying to feel interested.
'No, you don't understand,' the Knight said, looking a little vexed. 'That's what the name is called. The name really is "The Aged Aged Man".'
'Then I ought to have said "That's what the song is called"?' Alice corrected herself.
'No, you oughtn't: that's quite another thing! The song is called "Ways and Means": but that's only what it's called, you know!'
'Well, what is the song, then?' said Alice, who was by this time completely bewildered.
'I was coming to that,' the Knight said. 'The song really is "A-sitting On a Gate": and the tune's my own invention.'
这首歌,这首歌的名字,这首歌叫什么,这首歌叫什么,明显都不一样
以下三点千万不要混淆:
- 引用变量的位置 -- 别名。
- 引用变量的位置——别名变量。
- 如果引用变量是引用类型,则引用对象的位置(如果有)。
ref int x = ref DoSomething(data);
Is the value of x now on the stack or the heap?
表达式 x
是另一个变量 的 别名。
该变量有一个值。
假设别名变量是值类型。别名变量及其值是在临时池(又名 "stack")还是长期池("heap")中?我们不知道。我们也不在乎。我们知道,无论它是什么,我们都可以保证这个变量现在是活跃的。
但是我们可以猜测:ref 返回的变量通常 堆分配变量的别名,因为我们确定它们是活动的.
假设别名变量是引用类型。 引用是存储在栈上还是堆上?同样,出于同样的原因,我们也不知道。 那个引用 的引用对象是在栈上还是堆上?它要么在堆上,要么为空;我们保证这一点。
Or is x stored on the stack as a reference and the value on the heap?
x
是指 x
别名 的变量,还是 本地 x
本身?本地本身存储在堆栈或寄存器中;它永远不会被提升到闭包 class 的字段中。变量别名可以在任何地方,但如上所述,可能在堆上。
ref int x
是 int* x
的语法糖,变量在 运行 时的行为方式。当您将变量作为参数传递给方法并且参数被声明为 ref
时,您会得到完全相同的行为,调用者将指针传递给变量。指针不关心值存储在哪里,实际上可以存储在任何地方。请注意,您不能传递 属性,它没有存储空间。
他们在 C# v7 中必须做的重要事情是确保您不会意外创建 dangling pointer bug。在 C 和 C++ 等语言中臭名昭著,在这些语言中它是未定义的行为,不需要编译器生成诊断。许多具有该错误的程序似乎 运行 都很好,直到程序中看似微不足道的更改(添加函数调用)破坏了指向的值。
afaik 其实不难,被调用方法的局部变量是麻烦制造者。它们在方法 returns 之后不再存在,因此引用无效。在 C# v7 中给你一个编译错误的特定场景。但是如果局部变量是调用者之一,并且它通过参数传入引用,那么该变量仍然存在。
自从引入 C# 7.0 的 return by reference 功能以来,根据我的理解,像这样的功能需要对编译器进行一些重新布线,以便仅将此引用存储在位于堆上的变量上, 是否可以在堆栈上存储对变量的 returned 引用,或者新的 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:
Finally, the CLR does allow “ref return types”; you could in theory have a method “ref int M() { … }” that returned a reference to an integer variable. If for some bizarre reason we ever decided to allow that in C#, we’d have to fix up the compiler and verifier so that they ensured that it was only possible to return refs to variables that were known to be on the heap, or known to be “lower down” on the stack than the callee.
The name of the song is called "Haddocks' Eyes".' 'Oh, that's the name of the song, is it?' Alice said, trying to feel interested. 'No, you don't understand,' the Knight said, looking a little vexed. 'That's what the name is called. The name really is "The Aged Aged Man".' 'Then I ought to have said "That's what the song is called"?' Alice corrected herself. 'No, you oughtn't: that's quite another thing! The song is called "Ways and Means": but that's only what it's called, you know!' 'Well, what is the song, then?' said Alice, who was by this time completely bewildered. 'I was coming to that,' the Knight said. 'The song really is "A-sitting On a Gate": and the tune's my own invention.'
这首歌,这首歌的名字,这首歌叫什么,这首歌叫什么,明显都不一样
以下三点千万不要混淆:
- 引用变量的位置 -- 别名。
- 引用变量的位置——别名变量。
- 如果引用变量是引用类型,则引用对象的位置(如果有)。
ref int x = ref DoSomething(data);
Is the value of x now on the stack or the heap?
表达式 x
是另一个变量 的 别名。
该变量有一个值。
假设别名变量是值类型。别名变量及其值是在临时池(又名 "stack")还是长期池("heap")中?我们不知道。我们也不在乎。我们知道,无论它是什么,我们都可以保证这个变量现在是活跃的。
但是我们可以猜测:ref 返回的变量通常 堆分配变量的别名,因为我们确定它们是活动的.
假设别名变量是引用类型。 引用是存储在栈上还是堆上?同样,出于同样的原因,我们也不知道。 那个引用 的引用对象是在栈上还是堆上?它要么在堆上,要么为空;我们保证这一点。
Or is x stored on the stack as a reference and the value on the heap?
x
是指 x
别名 的变量,还是 本地 x
本身?本地本身存储在堆栈或寄存器中;它永远不会被提升到闭包 class 的字段中。变量别名可以在任何地方,但如上所述,可能在堆上。
ref int x
是 int* x
的语法糖,变量在 运行 时的行为方式。当您将变量作为参数传递给方法并且参数被声明为 ref
时,您会得到完全相同的行为,调用者将指针传递给变量。指针不关心值存储在哪里,实际上可以存储在任何地方。请注意,您不能传递 属性,它没有存储空间。
他们在 C# v7 中必须做的重要事情是确保您不会意外创建 dangling pointer bug。在 C 和 C++ 等语言中臭名昭著,在这些语言中它是未定义的行为,不需要编译器生成诊断。许多具有该错误的程序似乎 运行 都很好,直到程序中看似微不足道的更改(添加函数调用)破坏了指向的值。
afaik 其实不难,被调用方法的局部变量是麻烦制造者。它们在方法 returns 之后不再存在,因此引用无效。在 C# v7 中给你一个编译错误的特定场景。但是如果局部变量是调用者之一,并且它通过参数传入引用,那么该变量仍然存在。