在不使用其返回值的情况下调用非void函数。 究竟发生了什么?

所以,我在这里找到了一个类似的问题,但答案更多的是关于风格以及你是否能够做到这一点。

我的问题是,当你调用一个返回一个对象的非void函数时会发生什么,但是你从不分配或使用所述返回的对象? 所以,更少关于你是否可以,因为我完全知道你可以理解上面链接的另一个问题……编译器/运行时环境有什么作用?

这不是特定于语言的问题,但如果您回答,请说明您所指的语言,因为行为会有所不同。

我相信对于C#和Java,结果都会在堆栈上结束,然后编译器会强制使用pop指令来忽略它。 Eric Lippert关于“The void is invariant”的博客文章提供了更多相关信息。

例如,请考虑以下C#代码:

using System; public class Test { static int Foo() { return 10; } public static void Main() { Foo(); Foo(); } } 

Main方法生成的IL(通过MS C#4编译器)是:

 .method public hidebysig static void Main() cil managed { .entrypoint .maxstack 8 L_0000: call int32 Test::Foo() L_0005: pop L_0006: call int32 Test::Foo() L_000b: pop L_000c: ret } 

注意pop的调用 – 如果你使Foo成为void方法,它就会消失。

编译器做了什么?

编译器生成一个pop指令,该指令丢弃虚拟堆栈的结果。

运行时环境有什么作用?

它通常将代码嵌入到代码中,该代码将返回值传递回寄存器,而不是堆栈位置。 (通常是x86体系结构上的EAX。)

抖动知道该值将不被使用,因此它可能生成清除寄存器的代码。 或者它可能只是让它在寄存器中闲置一段时间。

您关心哪个运行时环境? 他们有很多,他们都有不同的紧张情绪。

它取决于所使用的调用约定。 对于小型/简单类型,返回通常发生在寄存器中。 在这种情况下,函数会将值写入寄存器,但是没有其他内容会引起注意,下次需要该寄存器时(通常会很快发生)它将被其他东西覆盖。

对于较大的类型,编译器通常会分配一个结构来保存返回值。 究竟在哪里/如何进行分配会因编译器而异 – 在某些情况下它将是一个静态结构,下次调用返回相同类型的函数时,内容将被忽略并被覆盖。 在其他情况下,它将在堆栈上,即使你没有使用它,它仍然需要在调用函数之前分配,然后释放

对于C ++,通常,编译器将优化变量的返回,将其转换为void函数,如果这允许进一步优化,编译器可以优化整个函数调用或仅与返回值有关的部分函数调用。 对于Java和C#,我不知道。

在.NET中,如果返回的对象是引用类型,并且应用程序没有对该对象的其他引用,那么在垃圾收集器决定收集它之前,您仍然会在内存中浮动一个对象。

如果返回的对象碰巧持有资源,这可能会很糟糕。 如果它实现了IDisposable接口,那么你的代码应该在它上面调用Dispose方法,但在这种情况下,永远不会调用Dispose方法。

编辑:纠正错字。