代码之家  ›  专栏  ›  技术社区  ›  Thom Smith

vbscript似乎以错误的顺序从嵌套范围中收集对象

  •  4
  • Thom Smith  · 技术社区  · 14 年前

    我有以下代码:

    function p (str)
        Response.Write VBLF & str
    end function
    
    function nop: end function
    
    class Test1
        private sub class_initialize
            p "Test1 Start"
        end sub
    
        private sub class_terminate
            p "Test1 End"
        end sub
    end class
    
    class Test2
        private sub class_initialize
            p "    Test2 Start"
        end sub
    
        private sub class_terminate
            p "    Test2 End"
        end sub
    end class
    

    当我跑步时:

    with new Test1
        with new Test2
        end with
    end with
    

    我预计产量:

    Test1 Start
        Test2 Start
        Test2 End
    Test1 End
    

    但我得到:

    Test1 Start
        Test2 Start
    Test1 End
        Test2 End
    

    但是,如果我运行以下任一项,我会得到我期望的结果:

    with new Test1
        with new Test2
            nop
        end with
    end with
    
    with new Test1
        with new Test2
        end with
        nop
    end with
    

    但不包括以下内容:

    with new Test1
        nop
        with new Test2
        end with
    end with
    

    vbscript有一个很强的保证,可以立即处理对象,我正在使用(滥用?)在我的申请中,这一保证有多种用途。没有 nop ,为什么要收集 Test1 Test2 按“错误”的顺序?

    1 回复  |  直到 14 年前
        1
  •  10
  •   Community Keith    7 年前

    多迷人的虫子啊。

    我手头没有vbscript引擎的调试版本。(我放在上面的那张10年前的硬盘,从我最后一次看它开始,在两年的时间里显然已经坏了。)不过,我可以很容易地猜出这是怎么回事。我的怀疑是,我没有将与“end with”相对应的指令标记为语句已结束且收集器必须运行的点。

    让我们考虑一下这个假设。

    在第一个示例中,GC何时运行?程序结束时。此时,终止符按创建对象的顺序运行。(这是不应依赖的实现细节。)

    在第二个和第三个示例中,对nop的调用结束会触发一个gc,而这恰好发生在end with旁边。(我不太清楚为什么第二个示例在对象符合收集条件时触发GC;我不记得codegen的确切语义,它将对象引用从WITH块范围中弹出。)

    在第四个示例中,GC是在内部with之前触发的,什么也不做。

    因为我编写了终止逻辑和相当数量的“with”处理代码,所以我毫无疑问地导致了这个错误,非常抱歉。显然,在过去的11年或12年里,我们都没有遇到任何大问题,而且由于它只影响没有内容的“with”块,所以我不认为它会被修复。

    无论如何,你不应该依赖终止订单。这是一个糟糕的编程实践。

    有关vbscript终止逻辑迷人主题的更多信息,请参见:

    What is the order of destruction of objects in VBScript?