Firedragon
Firedragon

Reputation: 3733

Creating new object in function call

I was wondering if it is safe to create new objects as part of a method (or indeed constructor call)

Such as the convuluted example below:

public class Igloo
{
    public int i = 5;
}

public class Program
{
    static void Main(string[] args)
    {
        DoSomething(new Igloo());
    }

    private static void DoSomething(Igloo i)
    {
        Debug.WriteLine(i.i);
    }
}

Is creating temporary objects like this frowned upon? Does the new object that is created get cleaned up properly.

Upvotes: 2

Views: 5756

Answers (5)

Justin
Justin

Reputation: 86729

SLaks is right - this is completely fine and is for all intents and purposes identical to doing the following:

Igloo igloo = new Igloo();
DoSomething(igloo);

In both cases as soon as the Igloo instance is passed to the DoSomething method - at this point the instance is no longer accessible from within the Main method making the instance elegible for collection once the DoSomething method has finished with it.


If we want to take a look at whats going on in more detail then take a peek at the IL:

.method private hidebysig static 
    void Main (string[] args) cil managed 
{
    // Method begins at RVA 0x2060
    // Code size 13 (0xd)
    .maxstack 8
    .entrypoint

    IL_0000: nop
    IL_0001: newobj instance void ConsoleApplication1.Igloo::.ctor()
    IL_0006: call void ConsoleApplication1.Program::DoSomething(class ConsoleApplication1.Igloo)
    IL_000b: nop
    IL_000c: ret
}

To explain what this means; We see that on IL_0001 that we create a new instance of Igloo - as the CLR is a stack based virtual machine this instruction pushes a reference to that instance onto the stack. The next instruction is the call to DoSomething - again the CLR is a stack based virtual machine and so arguments are pushed onto the stack from left to right (so that the last item on the stack is the right-most argument). In this case there is only 1 argument and its already on the stack as a result of the last operation and so we are ready to call our method.

If we compare this to the IL produced when we make the following modification:

Igloo igloo = new Igloo();
DoSomething(igloo);

We can see only a couple of important differences:

.method private hidebysig static 
    void Main (string[] args) cil managed 
{
    // Method begins at RVA 0x2060
    // Code size 15 (0xf)
    .maxstack 1
    .entrypoint
    .locals init (
        [0] class ConsoleApplication1.Igloo igloo
    )

    IL_0000: nop
    IL_0001: newobj instance void ConsoleApplication1.Igloo::.ctor()
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: call void ConsoleApplication1.Program::DoSomething(class ConsoleApplication1.Igloo)
    IL_000d: nop
    IL_000e: ret
}

Aside from at the start of the method where locals are declared the only difference is the stloc.0 and ldloc.0 calls in between creating Igloo and our call to DoSomething. What is this?

stloc.0 is an instruction to pop the last item off the stack and store it in the 0th local. Note at this point we no longer have the correct stack to call DoSomething (we need our Igloo instance to be at the top of the stack) this is what ldloc.0 is for - it pushes the 0th local (back) on to the stack. Essentially these two instructions are our assignment.

Note that when this gets compiled down to machine code by the JITer these two statements will almost certainly get optimised out.

Upvotes: 3

Oliver
Oliver

Reputation: 45071

If you create a Windows Form project instead of a console one, you'll find the following line in the program.cs:

Application.Run(new FormMain());

So it seems that MS also does exactly the same as default for a windows forms project.

Upvotes: 3

Yes, that is ok. The object will be automatically deleted later.

Upvotes: 1

rerun
rerun

Reputation: 25495

This is safe and standard in c# all the garbage collector will collect those objects once they become unreachable.

Upvotes: 1

SLaks
SLaks

Reputation: 887225

There is nothing wrong with that.

In release mode, creating a variable for the object should end up compiling to the same IL (disclaimer: I haven't checked).

Upvotes: 6

Related Questions