所以,我发现了一个类似的问题here,但答案更多的是关于风格以及你是否能够做到。
我的问题是,当你调用一个返回一个对象的非void函数时,实际发生了什么,但你从未分配或使用所述返回的对象?所以,更少关于你是否可以,因为我完全知道你可以理解上面链接的另一个问题......编译器/运行时环境是做什么的?
这不是特定于语言的问题,但如果您回答,请说明您所指的语言,因为行为会有所不同。
答案 0 :(得分:16)
我相信对于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
成为无效方法,则会消失。
答案 1 :(得分:7)
编译器做了什么?
编译器生成一条pop指令,用于丢弃虚拟堆栈的结果。
运行时环境是做什么的?
它通常将代码嵌入到代码中,该代码将返回值传递回寄存器,而不是堆栈位置。 (通常是x86体系结构上的EAX。)
抖动知道该值将不被使用,因此它可能会生成清除寄存器的代码。或许它只是让它在寄存器中闲置一段时间。
您关心哪个运行时环境?他们有很多,他们都有不同的紧张情绪。
答案 2 :(得分:3)
它取决于所使用的调用约定。对于小型/简单类型,返回通常发生在寄存器中。在这种情况下,函数会将值写入寄存器,但没有其他任何内容会引起注意,下次需要该寄存器时(通常会很快发生)它将被其他东西覆盖。
对于较大的类型,编译器通常会分配一个结构来保存返回值。究竟在哪里/如何进行分配会因编译器而异 - 在某些情况下它将是一个静态结构,下次调用返回相同类型的函数时,内容将被忽略并被覆盖。在其他情况下,它将在堆栈上,即使你没有使用它,它仍然需要在调用函数之前分配,然后释放
答案 3 :(得分:1)
在.NET中,如果返回的对象是引用类型,并且应用程序没有对该对象的其他引用,那么在垃圾收集器决定收集它之前,您仍然会在内存中浮动一个对象。 / p>
如果返回的对象碰巧持有资源,这可能会很糟糕。如果它实现了IDisposable
接口,那么你的代码应该在它上面调用Dispose方法,但在这种情况下,永远不会调用Dispose方法。
编辑:纠正错字。
答案 4 :(得分:1)
对于C ++,通常,编译器会优化变量的返回,将其转换为void函数,如果这样可以进一步优化,编译器可以优化整个函数调用或其中仅属于返回值。对于Java和C#,我不知道。