所以,我在这里找到了一个类似的问题,但答案更多的是关于风格以及你是否能够做到。
我的问题是,当您调用返回对象的非 void 函数但您从未分配或使用所述返回对象时,实际上会发生什么?所以,少说你是否可以,因为我绝对知道你可以并且理解上面链接的另一个问题......编译器/运行时环境做什么?
这不是特定于语言的问题,但如果您回答,请说明您所指的语言,因为行为会有所不同。
我相信对于 C# 和 Java,结果最终都会在堆栈上,然后编译器会强制弹出指令忽略它。Eric Lippert 的博客文章“The void is invariant”对此提供了更多信息。
例如,考虑以下 C# 代码:
using System;
public class Test
{
static int Foo() { return 10; }
public static void Main()
{
Foo();
Foo();
}
}
为该方法生成的 IL(由 MS C# 4 编译器)Main
是:
.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 方法,这些调用就会消失。
编译器是做什么的?
编译器生成一条弹出指令,将结果从虚拟堆栈中丢弃。
运行时环境是做什么的?
它通常将代码转换为将返回值传回寄存器而不是堆栈位置的代码。(通常是 x86 架构上的 EAX。)
抖动知道该值将未被使用,因此它可能会生成清除寄存器的代码。或者也许它只是让它在寄存器中徘徊一段时间。
您关心哪个运行时环境?它们有很多,而且它们都有不同的抖动。
这在一定程度上取决于所使用的调用约定。对于小型/简单类型,返回通常发生在寄存器中。在这种情况下,该函数会将值写入寄存器,但不会注意其他任何事情,并且下次需要该寄存器时(通常会很快发生),它将被其他内容覆盖。
对于较大的类型,编译器通常会分配一个结构来保存返回值。但是,分配的确切位置/方式会因编译器而异——在某些情况下,它将是一个静态结构,并且下次调用返回相同类型的函数时,内容将被忽略并覆盖。在其他情况下它会在堆栈上,即使你没有使用它,它仍然需要在调用函数之前分配,然后释放
在 .NET 中,如果返回的对象是引用类型,并且应用程序没有对该对象的其他引用,那么在垃圾收集器决定收集它之前,您仍然会有一个对象在内存中浮动。
如果返回的对象碰巧持有资源,这可能会很糟糕。如果它实现了IDisposable
接口,那么你的代码应该调用它的 Dispose 方法,但在这种情况下,永远不会调用 Dispose 方法。
编辑:更正了一个错字。
对于 C++,编译器通常会优化变量的返回,将其转换为 void 函数,如果这样可以进一步优化,编译器可能会优化整个函数调用或仅与返回值有关的部分函数调用. 对于 Java 和 C#,我几乎没有什么想法。