It is common knowledge that a struct
is a value type, and is therefore allocated on the stack (except for specific cases where it is boxed in a class for instance).
However let's consider this struct
:
public struct TestStruct
{
public List<int> items;
}
internal class Program
{
private static void Main(string[] args)
{
TestStruct g;
}
}
Our TestStruct
g
is not a member of a class, but a "standalone" variable declared in the Main
function. It fits the requirements of a stack
-allocated variable.
However, if I write:
g.items = new List<int>();
items
is allocated on the heap
isn't it? Does g
"go"
on the heap
as well?items
when g
goes out of scope (i.e. does the
GC
have to do its job for items
)?List<int>
we had a variable of type
implementing IDisposable
, what would be the best course of action?PS: I know one could (should?) use a class
in this case instead of a struct
. I'm just being confused by this specific case.
I suppose items is allocated on the heap isn't it?
Yes. Memory for items
will be allocated on the heap.
Does g "go" on the heap as well?
No, struct stays on stack. It just has field which holds reference to items
list on heap.
What happens for items when g goes out of scope (i.e. does the GC have to do its job for items)?
If g
goes out of scope, then there will be no references to items
in application roots. Items will become garbage and will be collected by GC during next garbage collection. Until then items
will stay in memory (struct instance will be removed when you'll exit method where you used it).
What if instead of a List we had a variable of type implementing IDisposable, what would be the best course of action?
Best action is implementing IDisposable
by your struct. UPDATE: Actually as @MarcGravell pointed - if possible, its better not to use struct in this case.
and is therefore allocated on the stack (except for specific cases where it is boxed in a class for instance).
Is wrong. It is allocated as part of the declaring scope. There are probably more scenarios where it is actually on the heap than on the stack (simply: as part of another object - not an object itself), so this is not a good rule.
For your specific questions:
items
refers to (the new List<int>()
) goes on the heap; the field items
is part of the struct
, where-ever that is (and just holds the reference - essentially a glorified pointer)TestStruct
instance, then your best bet then would be for TestStruct
to actually be a class
that implements IDisposable
, and call Dispose()
from the class's Dispose()
As additional thoughts: being able to write g.items = new List<int>();
to me indicates that this is a very poor choice of a struct
, since mutability and struct
do not play nicely together (with lots of unexpected bugs possible). Either:
struct
immutable (i.e. a readonly
field, initialized in a custom constructor)class
In either case: a public
field is a bad choice - it should really be a property with a get
(and possibly a set
, if it is a class
- but probably not if it remains a struct
)
Examples:
public struct TestStruct {
private readonly List<int> items;
public List<int> Items { get { return items; } }
public TestStruct(List<int> items) {
this.items = items;
}
}
or:
public sealed class TestClass : IDisposable {
private SomeDisposable items = new SomeDisposable();
public SomeDisposable Items { get { return items; } }
public void Dispose() {
if(items != null) {
items.Dispose();
items = null;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With