开发者

Emulating pass by ref in C++/CLI without using tracking reference (%)?

开发者 https://www.devze.com 2022-12-15 15:42 出处:网络
I want to emulate the following method: ref class Something{ void foo(array<double>^% data) { data = gcnew array<double>(10);

I want to emulate the following method:

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

Such that, the caller's array gets mo开发者_StackOverflow社区dified/created. Nevertheless, there are some constrains:

  1. foo cannot use ref/out/% nor any additional parameters.
  2. the actual parameter of foo has to be Object^.

Is it possible to do it with unmanaged pointers, IntPtr or a more obscure way?


No. If the actual parameter of foo is a handle to an object, there is no way to change the calling stack's reference.

You need to use a tracking reference in order to be able to effect the handle passed into your method.


Edit in response to AZ's comment:

The reason this doesn't work, is that when you pass an Object handle, effectively, you're passing nothing but the location of the object in memory. At its core, this is basically just an integer holding the memory location.

When you assign a new object in your method, you're overriding that location (putting a new integer in place). That doesn't change the caller's original handle, since it's just a copy. This is the normal way of passing parameters.

By using a tracking reference, you're passing a reference to the location in memory. It's sort of like passing a pointer in C or C++. When you do that, you can change the location the reference points to (it's value) without changing the reference itself - only changing what it is referencing.


  1. foo cannot use ref/out/% nor any additional parameters.
  2. the actual parameter of foo has to be Object^.

The caller could allocate the array and pass it in, and you could modify elements within the array - but this is just casting the array to Object and back again.

If you want to change the actual array - eg assign it to a new array of different length, without using ref (% in C++/CLI) or out ([Out] in C++/CLI), you can't do it.

Here's why:

The .NET virtual machine works by pushing and popping things onto a stack. The way you pass parameters to functions works like this behind the scenes:

  1. You Push the parameters (in this case, a reference to the array) onto the stack.
  2. You Call the function
  3. The VM sets up for the method call by reading these values off the stack in the specified order, and assigning them to local variables in your function.
  4. The code inside the function runs.

If the caller doesn't put valid data on the stack before invoking the function, it crashes. If the caller puts data in the wrong order - it crashes. If anything is funny with the stack at all - it crashes.

Additionally, methods cannot modify things that are already on the stack. (If they did, they would corrupt the stack - it crashes), they can only push and pop new things on and off the stack.

This means 2 things:

  1. In order to call the function, you have to put a reference to the array onto the stack. Therefore the caller has to allocate the array itself, or pass a null reference.

  2. You can't change the reference to the array, so the function can't provide a new array. As arrays are inherently non-resizeable, this means that you can't add new elements (you can however change existing elements)

Disclaimer: Eric lippert is probably going to come and explain why everything I've just written is wrong, but to the best of my knowledge and research, that's how it works

0

精彩评论

暂无评论...
验证码 换一张
取 消