【问题标题】:Pointer reset once method called second time指针重置一次方法调用第二次
【发布时间】:2019-05-17 08:26:05
【问题描述】:

有人能解释一下为什么在第二次调用 IsAMatch 时头部和尾部会重置为 null,即使 id 将新指针传递给它,旧的指针也会被重置。

我在 c++ 上有等效的脚本,它运行良好。

有什么想法吗?
my code

这里的小代码示例会打印 10,20,因此第二次调用会更改第一个结构

class Program
{
    static unsafe void Main(string[] args)
    {

        MyStruct* myStruct = null;

        ChangeMe(ref myStruct, 10);

        Console.WriteLine(myStruct->num);

        MyStruct* myStruct2 = null;
        ChangeMe(ref myStruct2,20);

        Console.WriteLine(myStruct->num);

        Console.ReadKey();
    }

    public static unsafe void ChangeMe(ref MyStruct* h, int v)
    {
        MyStruct myStructNew = new MyStruct(v);

        h = &myStructNew;
    }

    public unsafe struct MyStruct
    {
        public int num;

        public MyStruct(int n)
        {
            num = n;
        }
    }
}

【问题讨论】:

  • 你必须记住.NET使用压缩GC,这意味着不使用fixed statement,内存可以在任意两条指令之间改变(技术上GC只在分配时调用,所以在任何新调用时) ,因此您的指针可能会指向您不希望它们指向的地方。正常引用会被 GC 更正,但指针不会。
  • @MadKarel 好的,所以可以按预期工作吗?添加固定语句?
  • @IronHide 这取决于您实际想要实现的目标。这看起来有点像 XY 问题,如果我们知道除了代码之外您真正想要发生的事情,我们可以提供最好的帮助。我怀疑这可以在没有指针的情况下解决。您链接到的代码看起来像是来自某个自动转换器,这可能会带来很大的问题。
  • 看我的回答,你的问题不在于GC,而在于C#中class和struct的区别。

标签: c# pointers ref unsafe


【解决方案1】:

你基本上是在返回一个指向局部变量的指针,这是完全错误的。

C# new 关键字和 C++ new 关键字之间存在差异,或者更确切地说,它与 C# 中的 classstruct 的交互之间存在差异。在 C++ 中,new 始终表示堆上的分配,您需要手动解除分配。在 C# 中,new 调用 class 表示堆分配,但 new 调用 struct 只是初始化局部变量。

这个 C# 代码:

MyStruct myStructNew = new MyStruct(v);

相当于这个 C++ 代码

MyStruct myStructNew{v};

C# struct 关键字创建一个值类型,这意味着在您的情况下它被分配在堆栈上。然后,从ChangeMe 返回后,堆栈递减,释放局部变量。在第二次调用时,堆栈再次递增,为第二次调用分配局部变量。当您调用相同的方法时,第二个MyStruct myStructNew 将使用相同的堆栈位置。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-26
    • 1970-01-01
    • 2022-11-24
    • 2015-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-31
    相关资源
    最近更新 更多