什么时候可以安全地从堆栈分配的变量/缓冲区返回初始化的Span <t>?

时间:2018-10-08 07:36:48

标签: .net memory stack c#-7.3

在以下两个示例中,返回Span<byte>(更一般地说Span<T>是安全的)是,从某种意义上说,当方法返回时,返回的Span<T>实例指向的内存位置仍然包含有意义的数据:

  static class Example {

    public static void Main() {
      var n = 0x0102030405060708U;
      var n_bytes_as_span_of_byte = n.ToBytesExtension();
      var n2 = 0x8899aabbccddeeffU; // <- will this "overwrite" span-contents above?
      //Do something with both n2 and n_bytes_as_span_of_byte...

      //Do something with StackAllocExtensions
    }


    [MethodImpl(MethodImplOptions.AggressiveInlining)]
   public static unsafe Span<byte> ToBytesExtension(
      this ulong num // <- Will making it 'ref' make any difference: 'this ref ulong num'?
    ) => new Span<byte>( // <- Will returning it by 'ref' make any difference: ... => ref ...?
      Unsafe.AsPointer(ref num) // <- What if we use '&num' instead of 'Unsafe.AsPointer(ref num)'
      , sizeof(ulong));


      [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static Span<byte> StackAllocExtensionThatDoesNotCompile(ulong someArg) {
      Span<byte> span = stackalloc byte[16];
      //Do something with span and someArg...

      return span; // <- Does not work: Cannot use local 'span' in this context because it may expose referenced variables outside of their declaration scope.
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static unsafe Span<byte> StackAllocExtensionThatCompiles(ulong someArg) {
      var byte_pointer = stackalloc byte[16];
      //Do something with span and someArg...

      return new Span<byte>(byte_pointer, 16); // <- But isn't this the same as above? I.e. "exposes referenced variables outside of their declaration scope"?
    }

  }

也:

  • 使用ref returnref参数如何影响(如果有的话)?
  • 内联有什么区别吗?

1 个答案:

答案 0 :(得分:1)

这是不安全的,因为不再保证使用stackalloc分配的内存在函数退出后仍然可用。

在所有这种情况下,您都使用不安全的设施来覆盖警告。使用不安全的代码,您可以做任何您想做的事情。例如,您可以返回不安全的堆栈(int)上的int x = 0; return &x;指针。

这不可能是其他方式,因为语言或运行时无法通过这些不安全的设施来跟踪生命周期。即使可以跟踪它,也会破坏stackalloc的性能优势。 stackalloc的存储速度很快,因为已知它会在函数退出时释放。