C#中的ref和out是否与C ++中的指针相同?

我只是用C#做了一个Swap例程:

static void Swap(ref int x, ref int y) { int temp = x; x = y; y = temp; } 

它与C ++代码的作用相同:

 void swap(int *d1, int *d2) { int temp=*d1; *d1=*d2; *d2=temp; } 

那些refout关键字如C#的指针而不使用unsafe代码?

他们更有限。 你可以在指针上说++,但不能在refout


编辑评论中的一些混淆,所以要绝对清楚:这里的要点是与指针的function进行比较。 您不能在ref / out上执行与ptr++相同的操作,即使其处理内存中的相邻位置。 你可以执行等价的(*ptr)++ ,这是真的(但不相关),但这可以将它与的function进行比较,而不是指针。


可以肯定的是,它们在内部只是指针,因为堆栈不会被移动并且C#经过精心组织,因此refout总是指向堆栈的活动区域。


编辑要再次绝对清楚(如果从下面的例子中已经不清楚),这里的重点不是ref / out 只能指向堆栈。 它指向堆栈时,语言规则保证不会成为悬空指针。 这种保证是必要的(并且相关/有趣),因为堆栈只是根据方法调用退出丢弃信息,没有检查以确保任何引用仍然存在。

相反,当ref / out引用GC堆中的对象时,这些对象只要有必要就能保持活动就不足为奇了:GC堆的设计正是为了保留引用者所需的任何时间长度的对象。 ,并提供固定(参见下面的示例)以支持不能通过GC压缩移动对象的情况。


如果您在不安全的代码中使用互操作,您会发现ref与指针密切相关。 例如,如果COM接口声明如下:

 HRESULT Write(BYTE *pBuffer, UINT size); 

互操作程序集将把它变成这样:

 void Write(ref byte pBuffer, uint size); 

你可以这样做来调用它(我相信COM互操作的东西负责固定数组):

 byte[] b = new byte[1000]; obj.Write(ref b[0], b.Length); 

换句话说, ref第一个字节可以访问所有内容; 它显然是指向第一个字节的指针。

C#中的引用参数可用于替换指针的一种用法,是的。 但不是所有的。

指针的另一个常见用途是作为迭代数组的手段。 Out / ref参数不能这样做,所以不,它们不是“与指针相同”。

refout仅与函数参数一起使用,表示参数将通过引用而不是值传递。 从这个意义上讲,是的,它们有点像C ++中的指针(实际上更像是引用)。 在本文中阅读更多相关信息。

实际上,我将它们与C ++引用而不是指针进行比较。 在C ++和C中,指针是一个更通用的概念,引用将做你想要的。

当然,所有这些都无疑是封面的指针。

使用的好处是你可以保证为项目分配一个值 – 如果没有,你将得到一个编译错误。

虽然比较在旁观者的眼中……我说不。 ‘ref’改变了调用约定,但没有改变参数的类型 。 在您的C ++示例中,d1和d2的类型为int *。 在C#中,它们仍然是Int32,它们恰好通过引用而不是值传递。

顺便说一句,你的C ++代码并没有真正交换传统意义上的输入。 像这样概括:

 template void swap(T *d1, T *d2) { T temp = *d1; *d1 = *d2; *d2 = temp; } 

…除非所有类型的T都有拷贝构造函数,否则将无法工作,即使这样,交换指针的效率也会低得多。

简短的答案是肯定的(类似的function,但不完全相同的机制)。 作为旁注,如果您使用FxCop分析您的代码,使用outref将导致“Microsoft.Design”错误“CA1045:DoNotPassTypesByReference”。