C# 为什么stackalloc必须用作变量初始值设定项?
我正在用C#(后续)编写一些不安全的代码,我想知道,为什么关键字必须用作变量初始值设定项?e、 g.这将产生语法错误:C# 为什么stackalloc必须用作变量初始值设定项?,c#,.net,pointers,unsafe,stackalloc,C#,.net,Pointers,Unsafe,Stackalloc,我正在用C#(后续)编写一些不安全的代码,我想知道,为什么关键字必须用作变量初始值设定项?e、 g.这将产生语法错误: public unsafe class UnsafeStream { byte* buffer; public UnsafeStream(int capacity) { this.buffer = stackalloc byte[capacity]; // "Invalid expression term 'stackalloc' /
public unsafe class UnsafeStream
{
byte* buffer;
public UnsafeStream(int capacity)
{
this.buffer = stackalloc byte[capacity]; // "Invalid expression term 'stackalloc' / ; expected / } expected"
}
}
但重新分配本地临时文件的结果不会:
public UnsafeStream(int capacity)
{
byte* buffer = stackalloc byte[capacity];
this.buffer = buffer;
}
为什么第一个版本不被允许,如果我尝试第二个版本,会发生什么坏事?您的堆栈看起来非常粗略,如下所示:
[stuff from earlier calls][stuff about where this came from][this][capacity]
^You are here
然后执行stackalloc
,这会向堆栈中添加两个内容,指针和指向的数组:
[stuff from earlier calls][stuff about where this came from][this][capacity][buffer][array pointed to by buffer]
^You are here
然后,当您返回最近放在堆栈上的内容时,当前函数的局部变量、其返回地址和stackalloc
ed缓冲区都被忽略(这是stackalloc
的优点之一,忽略内容既快又容易):
它可以被下一个方法调用覆盖:
[stuff from earlier calls][stuff about where this came from][this][new local1][new local2]o by buffer]
^You are here
您的建议是,私有字段,也就是堆上对象的一部分(不同的内存段,管理方式不同)包含一个指向缓冲区的指针,该缓冲区已被完全不同类型的数据半覆盖
直接后果将是:
缓冲区
现在很麻烦,因为其中一半被项覆盖,其中大部分甚至不是字节缓冲区的更改可能会在随机位置用随机字节覆盖它们
它也不是很有用。您可以通过足够的努力强制一个字段将地址保存到堆栈上的某个位置,但这并不是一个好办法。为什么要将堆栈上的数据分配给成员?@BrianRasmussen基本上,我希望制作一个更快的
MemoryStream
(如UnmanagedMemoryStream
,除了便携版之外)它使用指针和长度而不是数组。字段的使用寿命比堆栈内存的使用寿命长。当地人没有。如果您不了解这是如何工作的,那么在您了解之前不要使用不安全的代码。不安全代码适用于完全了解内存管理的专家。除了其他人提到的问题外,在执行此操作时,您还可以快速填满堆栈。有了这样的内存流想法,您可能希望仔细衡量几乎每件小事的影响,因为很容易做一些看起来会加快速度,实际上会让速度变慢的事情。或者单独加速,然后在实践中减慢。Stackalloc通常会让事情变得慢一些,即使你在测试中使用其他线程对堆施加压力,也会使的影响变得更糟。有道理,我接受你的答案。任何原因,特别是为什么要重新分配给局部变量,例如byte*buffer;缓冲区=stackalloc字节[123]代码>也被禁止?@JamesKo我猜是因为字节*缓冲区代码>正在进行分配吗?此外,它还允许您有条件地分配给堆而不是堆栈,我相信这会破坏某些东西。@Rob不一定是真的,您可以设置byte*buffer=null
,但它不会这样做(当然指针变量本身除外)。您可以重新分配给另一个变量,或者在stackalloc
之后重新分配buffer
。虽然这很方便(比如修复了),但您必须坚持使用一个初始化为该内存块地址的变量,因为该内存块将在方法的生命周期内被分割,并且您不希望代码的行为与此不同。
[stuff from earlier calls][stuff about where this came from][this][new local1][new local2]o by buffer]
^You are here