5

I'm reading through Jon Skeet's book reviews and he is going over the numerous inaccuracies of Head First C#.

One of them caught my eye:

[Under Errors Section] Claiming that structs always live on the stack.

In what situations would structs not live on the stack? This goes contrary to what I thought I knew about structs.

James B
  • 8,183
  • 4
  • 33
  • 40
mmcdole
  • 91,488
  • 60
  • 186
  • 222

6 Answers6

7

One common example is where the struct is a member of an object that is allocated in the heap. There is lots of additional detail in this question here. What’s the difference between struct and class in .Net?

Community
  • 1
  • 1
1800 INFORMATION
  • 131,367
  • 29
  • 160
  • 239
  • but isnt a struct nearly ALWAYS a member of an object that is allocated on the heap? isnt this the case everywhere except when the struct is just a local variable? – Simon_Weaver Feb 13 '09 at 01:25
  • Almost everywhere. A struct can also be a static member of a class, in which case it is not a member of an object and is nevertheless allocated on the heap. – yfeldblum Feb 13 '09 at 01:43
  • @Simon_Weaver A value type variable passed to a method. It doesn't have to be defined in a method. You're confusing mechanics with frequency-in-use. Mechanics is what matters, not how often it's used. – Lee Louviere Jan 26 '12 at 20:32
4

Whenever they are a field on a class

Unusual examples of this:

a: When a value-type variable is captured:

int i = 2;
Action action = delegate {i++;}
action();
Console.WriteLine(i);

This is compiled to something more like:

class Foo {
    public int i;
    public void Bar() {i++;}
}
...
Foo foo = new Foo();
foo.i = 2;
Action action = foo.Bar;
action();
Console.WriteLine(foo.i);

b: When a value-type variable is used in an iterator block:

IEnumerable<int> GetValues() {
   for(int i = 0 ; i < 5 ; i++) yield return i;
}

(the compiler generates a state machine to represent the iterator, of which all local variables (such as i) are fields)

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
2

When the instance of a value type gets boxed, the box, and hence the instance itself, gets moved to the heap. Although, there is got to be no doubting that a non-class member value type instance when first created is always created on the stack.

A struct is a value type. So it behaves as above.

G S
  • 35,511
  • 22
  • 84
  • 118
  • The boxed type itself is actually a reference type, mind you. Any value type has a sort of shadowy reference type version for boxing. It's a bit complicated. The "member of a class" case is much less arguable IMO :) – Jon Skeet Feb 10 '09 at 09:09
  • Technically, the value type is copied into the member of the box, which already exists on the heap. So it doesn't "move" to the heap. The term boxed-type is a misnomer. I find it easier if you want to have a value-type act as a reference-type, to have it already be a reference type. Value types should be reserved for immutable, or data transfer through a pipe to a 3rd party. – Lee Louviere Jan 26 '12 at 20:50
2

Just as an example of the answer from 1800 INFORMATION:

public class Foo
{
    int x;

    public Foo(int y)
    {
        x = y;
    }
}

...

Foo foo = new Foo(10);

Now, after the constructor has finished executing, the value of foo.x is 10. Where is foo.x in memory? On the heap. What's the type of foo.x? int aka System.Int32, which is a struct.

The other answers about captured variables and boxing etc are correct as well ("sort of" in the boxing case - I'll add a comment), but this example is the most simplest and most important one, IMO.

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • There are structs and enums - that's the lot, I believe. – Jon Skeet Feb 10 '09 at 09:19
  • .Net is weird. An int is a struct. As a C++ developer, that will take some getting used to – 1800 INFORMATION Feb 10 '09 at 09:22
  • a lot of the simple types are value-types. I think that was done to mirror expectations for people coming from most other languages, and for the sake of efficiency. It's simply better to copy an Int16, is it not? And making an Int32 a reference doubles its size. – Lee Louviere Jan 26 '12 at 20:47
0

Already mentioned in depth by others

  • Member field values
  • boxed structs (strictly they are then no longer value types)

In addition:

  • An array of structs resides entirely on the heap
  • static structs (not on the stack or the heap but in a special area all of their own)
ShuggyCoUk
  • 36,004
  • 6
  • 77
  • 101
0

The book made the mistake of confusing typing mechanics with scope mechanics. A Value type is not a reference type. It's data is copied when you call a method using it as an argument (without ref or out). Value types will live on the stack in the scope of a method, rather than on the heap as a reference object does, but that doesn't mean it will always live on the stack.

So, the book is making a usage statement in lieu of a mechanics statement, and confusing the two. It's not a total baseless claim, but it's wrong.

Value types will be held wherever their owner is.

So if their scope is a method, they'll be on the stack. If their scope is an object, they'll live with the object on the heap.

With that, it's pretty safe to say, a value-type is best left as an immutable, since most people have a hard time predicting the value-type mechanics of by-value.

Lee Louviere
  • 5,162
  • 30
  • 54