Are Structs always stack allocated or sometimes heap allocated?
Asked Answered
P

8

60

I was of the impression that in C#, struct elements are allocated on the stack and thus disappear when returning from a method in which they were created. But what happens if I place the struct-values in a list and return that? The elements survives. Are struct instances sometimes allocated on the heap?

internal struct Stru
{
  public int i;
}

internal class StruTry
{
  public List<Stru> Get(int max)
  {
    var l = new List<Stru>();
    for (int i = 0; i < max; i++)
      l.Add(new Stru {i=i});

    return l;
  }
}

code printing 0, 1, 2

[Test]
public void T()
{
  var ll = new StruTry().Get(3);
  foreach (var stru in ll)
    Console.WriteLine("* "+ stru.i);
}
Payment answered 31/1, 2011 at 16:19 Comment(0)
O
82

First, read this post from Eric Lippert on The Stack is an Implementation Detail. Follow it with The Truth about Value Types. As for your specific question

Are struct instances sometimes allocated on the heap?

Yes, they are sometimes allocated on the heap. There are lots of examples of when they could be allocated on the heap. If they are boxed, or if they are fields in a class, or if they are elements of an array, or if they are the value of a variable of value type that has been closed over, etc.

But what happens if I place the struct-values in a list and return that? The elements survives.

You're thinking about this the right way, and this is one of the salient points on where a value type might be allocated. See the second post that I referred to on The Truth About Value Types for more details. But just keep The Stack is an Implementation Detail in mind. The key takeaway is that you really don't need to concern yourself with this stuff. You should be concerned with the semantic difference between value types and reference types.

Ocieock answered 31/1, 2011 at 16:22 Comment(4)
That last point about only being concerned with "am I passing by value or by reference" and not "is my object on the stack or the heap" - is difficult for me because I mostly program in C++. I think any C/C++ programmer thinks in terms of where an object lives. In C/C++ structs (and classes in C++) can live in either place depending how they are declared. It seems that the main thing for any C/C++ programmer to work in C# is to break this habit and never think about where an object lives.Cutaway
@Ocieock How about generic structures like struct sockaddr, how can it be stack allocated without knowing the right size of it (since this generic structure is by definition smaller that the IPv6 structure sockaddr_in6)Hematite
@Ocieock What does this mean "if they are the value of a variable of value type that has been closed over"?Schoolmaster
@Schoolmaster check closureDogie
G
30

Structs are like ints. If you have a local int, it will generally be on the stack, if you have a list of ints, they are stored directly in the list's internal array, which is on the heap. Structs behave the same way.

Gatekeeper answered 31/1, 2011 at 16:23 Comment(1)
Sweet. I have a array in a struct I want to defined and was very worried that the values in that struct would eat up the stack. Glad to hear that the array won't eat into the struct. Heap has (seemingly) indefinite space!!!Depression
W
7

But what happens if I place the struct-values in a list and return that? The elements survives.

Technically the values added to the 'List' are not the same values, they are value based copies. If, for example, you modify the original, those changes will not be carried to the copy in the list. Also, 'List' returns a copy of the value at the indicated index. This means if the struct is mutable and you modify the value returned from the 'List', then the value in the List<t> will remain unchanged. This is not the case with arrays, as the array index provides access to the actual variable.

Wingding answered 13/2, 2013 at 20:37 Comment(0)
T
2

All types can sometime be allocated on the heap. Besides which, heap/stack is an implementation detail of the CLR and not in the C# spec, so you shouldn't ever rely on such things. See here for a good blog post on this subject.

Taffy answered 31/1, 2011 at 16:23 Comment(0)
U
1

From what I remember...

The location of value types depends on where they are declared. Method variables are allocated, stored on the stack and removed after execution of the method in the stack frame. Value types declared as part of a reference type are stored on the heap within the structure of the enclosing type.

Let me know if I am wrong!

Unplaced answered 31/1, 2011 at 16:24 Comment(1)
If by "method variable" you mean local variable, your statement is not completely accurate. For example, if the local variable is closed over in a lambda expression, it will be hoisted to be a member of compiled-defined class and will be allocated on the heap just like other fields of a class. The key is that such a local variable could live longer than the defining method and therefore needs to be allocated away from the stack.Ocieock
D
1

A storage location (variable, field, parameter, array slot, etc.) of struct type holds the struct's public and private fields within it. If that storage location is on the stack, the struct's fields will be on the stack. If it is within another class or struct, then the struct's fields will be stored as part of that other class or struct instance.

A storage location of class type holds a reference to a complete class object which is always either (1) stored somewhere completely separate from the storage location holding a reference, or (2) the class object of which that storage location is a field.

Differential answered 15/2, 2013 at 20:28 Comment(0)
W
0

With C# 7.2 you can declare struct which is always allocated on stack and will not be put into heap - using ref keyword:

public ref struct MyStackStruct
{
..

But it has many limitations.

All details are in official docs: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/ref-struct

Whimwham answered 19/4, 2024 at 12:9 Comment(1)
Also you can pass a struct by the ref keyword and it wont be placed on the heap - it will be something like passing non-primitive type by reference without heap :DDewan
D
0

There is also another example that I did not see in the above comments: if a struct is a static field then also it will be stored in the heap.

Dewan answered 16/5, 2024 at 7:53 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.