【问题标题】:Reusing of survived local variable in each call. UB?在每次调用中重用幸存的局部变量。 UB?
【发布时间】:2016-12-28 11:49:15
【问题描述】:

我是 C# 新手。我遇到了这样的代码示例:

namespace App1
{
    delegate int Sum(int number);

    class TestAnonymusMethod
    {
        static Sum m()
        {
            int result = 0;  // is not zeroed between calls

            Sum del = delegate (int number)
            {
                for (int i = 0;  i <= number;  i++)
                    result += i;
                return result;
            };
            return del;
        }

        static void Main()
        {
            Sum del1 = m();

            for (int i = 1;  i <= 5;  i++)
                Console.WriteLine("Sum of {0} == {1}", i, del1(i));

            Console.ReadKey();
        }
    }
}

输出是:

Sum of 1 == 1
Sum of 2 == 4
Sum of 3 == 10
Sum of 4 == 20
Sum of 5 == 35

如您所见,局部变量 result 在调用之间未归零。它是“未定义的行为”吗?看起来这是因为当result 的范围关闭时,它的生命周期是未定义的。

但是在 C# 中重用活动实体的规则是什么?这是规则 - “总是重复使用”,还是在某些情况下,会创建新的而不是重复使用幸存的旧的?

【问题讨论】:

  • 为什么要归零?你只调用一次“m()”方法,所以它被初始化为 0 一次。
  • @Evk,我重命名了问题。由于result 不是static,它对我来说有点奇怪(在 C++ 之后) - 在每次调用中重用相同的变量(及其当前值)。

标签: c# delegates anonymous-function undefined-behavior


【解决方案1】:

是“未定义的行为”吗?

不,这是定义明确的行为 - 只是不是您期望的行为。

看起来这是因为当结果范围关闭时,它的生命周期是未定义的。

不,result 的生命周期超出了m() 的范围。来自 C# 5 规范第 7.15.5.1 节:

当一个外部变量被一个匿名函数引用时,这个外部变量被称为被匿名函数捕获。通常,局部变量的生命周期仅限于执行与其关联的块或语句(第 5.1.7 节)。但是,捕获的外部变量的生命周期至少会延长,直到从匿名函数创建的委托或表达式树符合垃圾回收条件。

【讨论】:

  • 谢谢!但是我对 7.15.5.1 的理解是否正确?:result 至少在del1 的范围被关闭之前会被保证活着?
  • @user1234567:不,直到委托可以进行垃圾收集。 del1 是一个局部变量,恰好引用了委托。您可以将该值传递给保留对同一委托的引用并使其保持活动状态的其他事物。基本上,委托拥有它需要的所有状态,包括result 变量。您需要考虑对象和垃圾收集,而不是变量和范围。
猜你喜欢
  • 1970-01-01
  • 2011-03-16
  • 2021-10-08
  • 1970-01-01
  • 1970-01-01
  • 2019-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多