Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the deep copy of struct type also disposed when in the block of “Using……”?

Suppose I have a struct type implementing IDisposible, and if I use the codes below:

using (MyStruct ms = new MyStruct())
{
     InnerAction(ms);   //Notice "InnerAction" is "InnerAction(MyStruct ms)"
}

Of course I see after the block of using, the ms is disposed. However what about the struct in "InnerAction"? Is it still alive because of deep copy or it is also disposed?

If it's still alive (not disposed), Must I use "ref" for "InnerAction"?

Please give me your proof:)

Thx all.

like image 469
xqMogvKW Avatar asked Jul 24 '15 07:07

xqMogvKW


People also ask

What is the source of deep and shallow copy of structure?

The source of deep and shallow copy of structure in C language If a structure contains pointer variables, dynamic memory is allocated during the use of the structure, and mutual assignments are made between variables of the same type of structure, shallow copy and deep copy problems will be caused. 2. Shallow copy problem

What does it mean when a list is deep copied?

It means that any changes made to a copy of object do not reflect in the original object. In python, this is implemented using “ deepcopy () ” function. In the above example, the change made in the list did not effect in other lists, indicating the list is deep copied.

What happens when you deep copy on an object?

This implies that, if perform you deep copy on an object that contains reference (object), both the original and copied object refers to different objects and, if you do any changes to the data the copied object they are not reflected in the original object.

What is deep copy in C++?

In Deep copy, an object is created by copying data of all variables and it also allocates similar memory resources with the same value to the object. In order to perform Deep copy, we need to explicitly define the copy constructor and assign dynamic memory as well if required.


1 Answers

It's worse than you think: ms is not even disposed.

The reason is that the using statement makes an internal copy which it calls dispose on in a try/finally construct.

Consider this LinqPad example:

void Main()
{
    MyStruct ms;
    using (ms = new MyStruct())
    {
        InnerAction(ms);
    }

    ms.IsDisposed.Dump();
    _naughtyCachedStruct.IsDisposed.Dump();
}

MyStruct _naughtyCachedStruct;

void InnerAction(MyStruct s)
{
    _naughtyCachedStruct = s;
}

struct MyStruct : IDisposable
{
    public Boolean IsDisposed { get; set; }

    public void Dispose()
    {
        IsDisposed = true;
    }
}

Here's some of the decompiled IL:

IL_0000:  nop         
IL_0001:  ldloca.s    01 // CS$0$0000
IL_0003:  initobj     UserQuery.MyStruct
IL_0009:  ldloc.1     // CS$0$0000
IL_000A:  dup         
IL_000B:  stloc.0     // ms
IL_000C:  dup         
IL_000D:  stloc.0     // ms
IL_000E:  stloc.2     // CS$3$0001
IL_000F:  nop         
IL_0010:  ldarg.0     
IL_0011:  ldloc.0     // ms

Notice that in IL_000E a compiler generated local (CS$3$0001) is created and a copy of ms is stored there. Later...

IL_001B:  ldloca.s    02 // CS$3$0001
IL_001D:  constrained. UserQuery.MyStruct
IL_0023:  callvirt    System.IDisposable.Dispose
IL_0028:  nop         
IL_0029:  endfinally  

Dispose is called against this local, not ms (which is stored in location 0).

The result is that both ms and the copy that InnerAction holds onto are both not disposed.

Conclusion: don't use structs in using statements.

EDIT: as @Weston points out in the comments, you can manually box the struct and act on the boxed instance, since it then lives on the heap. This way you can get the instance to dispose, but if you had cast it back to the struct in the using statement, you'll only end up storing a copy before the instance was disposed. Further, boxing removes the benefit of staying off the heap, which you are presumably up to here.

MyStruct ms = new MyStruct();
var disposable = (IDisposable)ms;
using (disposable)
{
    InnerAction(disposable);
}

((MyStruct)disposable).IsDisposed.Dump();
like image 138
codekaizen Avatar answered Oct 25 '22 01:10

codekaizen