在不使用跟踪引用(%)的情况下在C ++ / CLI中通过ref模拟传递?

时间:2010-01-08 00:32:16

标签: .net visual-c++ c++-cli

我想模仿以下方法:

ref class Something{
   void foo(array<double>^% data)
   {
      data = gcnew array<double>(10);
   }
};

这样,调用者的数组被修改/创建。然而,有一些限制因素:

  1. foo不能使用ref / out /%或任何其他参数。
  2. foo的实际参数必须是Object ^。
  3. 是否可以使用非托管指针,IntPtr或更隐蔽的方式来实现?

2 个答案:

答案 0 :(得分:2)

没有。如果foo的实际参数是对象的句柄,则无法更改调用堆栈的引用。

您需要使用跟踪引用才能影响传递给方法的句柄。


编辑以回应AZ的评论:

这不起作用的原因是,当你有效地传递一个Object句柄时,除了对象在内存中的位置外,你只传递它。从本质上讲,这基本上只是一个保存内存位置的整数。

在方法中指定新对象时,您将覆盖该位置(放置一个新整数)。这不会改变调用者的原始句柄,因为它只是一个副本。这是传递参数的常规方法。

通过使用跟踪引用,您将传递对内存中位置的引用。这有点像在C或C ++中传递指针。当您这样做时,您可以更改引用指向的位置(它的值)而不更改引用本身 - 仅更改它引用的内容。

答案 1 :(得分:1)

  
      
  1. foo不能使用ref / out /%或任何其他参数。
  2.   
  3. foo的实际参数必须是Object ^。
  4.   

调用者可以分配数组并将其传入,并且您可以修改数组中的元素 - 但这只是将数组转换为Object并再次返回。

如果要更改实际数组 - 例如将其分配给不同长度的新数组,而不使用ref(C ++ / CLI中为%)或out({{ 1}}在C ++ / CLI中,你不能这样做。

原因如下:

.NET虚拟机通过将内容推送到堆栈来工作。将参数传递给函数的方式在幕后工作如下:

  1. 您将参数(在本例中为对阵列的引用)推送到堆栈上。
  2. 您调用函数
  3. VM通过以指定顺序从堆栈中读取这些值并将它们分配给函数中的局部变量来设置方法调用。
  4. 该函数内的代码运行。
  5. 如果调用者在调用函数之前没有在栈上放置有效数据,它就会崩溃。如果调用者以错误的顺序放入数据 - 它会崩溃。如果堆栈中任何东西都很有趣 - 它会崩溃。

    此外,方法无法修改堆栈中已有的内容。 (如果他们这样做了,他们会破坏堆栈 - 崩溃),他们只能在堆栈上下推出新东西。

    这意味着两件事:

    1. 为了调用该函数,您必须将对数组的引用放入堆栈中。因此调用者必须自己分配数组,或传递空引用。

    2. 您无法更改对数组的引用,因此该函数无法提供新数组。由于数组本身不可调整大小,这意味着您无法添加新元素(但您可以更改现有元素)

    3. 免责声明:Eric lippert可能会来解释为什么我刚写的所有内容都是错误的,但就我所知和研究而言,这就是它的工作原理