Please Explain where will the struct be stored if it is declared inside the Class

T

thomson

Hi all,
Would you please explain me where will be the heap stored if it
is declared inside the Class, As class is a reference type, so it gets
stored on the heap, but struct is a value type-stored on the stack



Regards

thomson
 
B

Bruce Wood

No, a struct is not a value type stored on the stack.

A struct is a value type stored on the stack _if_ it is declared as a
local variable in a method.

A struct is a value type stored on the heap along with the rest of the
information for a class if the struct is declared as a member of the
class.

Remember: a struct is a value type just like an int or a double. If you
declare an int as a class member, where is it stored? A struct would be
stored in the same place. If you declare an int as a local variable in
a method, where is it stored? A struct would be stored in the same
place.
 
T

thomson

Hi bruce,
Frankly Iam in a bit of confusion with the answer you have
send, Can u explain me in detail


Regards

thomson
 
W

Willy Denoyette [MVP]

Daniel O'Connell said:
It doesn't get much more detailed than Jon's article:

http://yoda.arachsys.com/csharp/memory.html

Agreed, just one small remark though, The article states "Every static
variable is stored on the heap", this is not completely correct if Jon here
meant the GC heap.
Static variables are not stored on the GC heap, but they live on a private,
per application domain heap, more precisely, on the "High Frequency heap"
within the loader heap. So, if you ever wonder where the PairOfInts static
counter variable lives, well it's on the "High Frequency Heap".

Willy.
 
B

Bruce Wood

OK... forget about structs for a second. Let's talk only about native
types (like ints, longs, doubles, and floats) and classes.

There are only two places that things are stored in a running .NET
program. (Actually, as Willy pointed out, there are three: static
things are stored elsewhere, but we'll ignore those for now.) Something
can be stored either on the stack, or on the heap.

First, think about the stack. What is it? It is a place to store the
local variables that you declare in methods, and arguments to method
parameters. So, if you have code like this:

public decimal PowerOf(decimal value, int power)
{
decimal result = 1;
for (int i = 0; i < power; i++)
{
result *= power;
}
return result;
}
....
decimal x = PowerOf(2, 8);

Yes, I realize that this is a cheesy example (and the method doesn't
even work for negative powers), but take a look at what's going on here
with respect to the stack.

In the main program, down below, x is allocated on the stack because
it's a local (non-static) variable. 2 and 8 are copied onto the stack,
because they're arguments to PowerOf. Within PowerOf, result and i are
also allocated space on the stack because they're local variables. The
return value from PowerOf is also copied onto space allocated on the
stack, and then copied from that space into the variable x, which as
you recall was allocated space on the stack.

So, in this example, everything is happening on the stack. The heap
isn't involved at all.

A struct would act exactly the same as any of these decimals and ints.
A struct variable declared as a local (non-static) variable would be
allocated space on the stack. A struct passed to a method as an
argument would be _copied_ onto the stack (just as 2 and 8 were copied
onto the stack).

Now let's look at what happens with classes and the heap:

public class MyClass
{
private int classInt = 0;
private decimal classDecimal = 15.0;

public SomeOtherClass DoSomeStuff(YetAnotherClass
yetAnotherInstance)
{
SomeOtherClass someOtherInstance = new SomeOtherClass();
...
return someOtherInstance;
}
}
....
MyClass mine = new MyClass();
SomeOtherClass other = mine.DoSomeStuff(new YetAnotherClass());

Again, a silly method and a silly call, but let's look at what's going
on.

The first thing that happens is that a new instance of MyClass is
created _on the heap_, and a _reference_ to that instance (the space
allocated for the class information on the heap) is saved in "mine",
which is allocated _on the stack_ because it's a local variable. So
what was saved on the heap? Well. every instance of MyClass contains
two class members, "classInt" and "classDecimal". So, space for an int
and a decimal was reserved on the heap, those variables were
intialized, and a reference to that heap location (a pointer, if you
will) was saved in the variable "mine", which is located on the stack.

Every time we create a new instance of MyClass, space for yet another
int and decimal will be created on the heap.

Notice, however, that everything on the heap eventually comes back to
the stack. What is stored on the stack in the case of class instances
are _references_ or _pointers_ to the heap location where the class
information is stored.

The next thing that happens is that we create an instance of
YetAnotherClass in order to pass it to mine.DoSomeStuff. The instance
of YetAnotherClass is allocated space on the heap... space for whatever
class members it declares (we can't see the declaration, so we don't
know how much space it needs). Then, a reference to that instance of
YetAnotherClass is placed on the stack as an argument to DoSomeStuff.

DoSomeStuff creates a new instance of SomeOtherClass. Again, space for
whatever members SomeOtherClass defines is reserved on the heap, and
the members of SomeOtherClass are initialized into that heap space. A
reference (or pointer) to this instance is stored in someOtherInstance
on the stack (because someOtherInstance is a local variable).

When DoSomeStuff returns, it copies the reference (pointer) to the
instance of SomeOtherClass into space allocated on the stack for its
return value. Back in the main program, this reference is copied into
the variable "other", which has space reserved on the stack (because
it's a local variable to the main program). So, we're left with "other"
containing a reference (pointer) to an instance of SomeOtherClass,
which stores its members in space on the heap.

So, now, what about structs? Well, if we were to change classInt and
classDecimal to user-defined struct types, _nothing would change_. When
space was allocated for MyClass on the heap, .NET would allocate enough
space to hold all of the information for the two structs, just as
though they were ints or decimals. It would initialize the space for
those structs with some intial values, just as you would initialize an
int or a decimal, and then it would put a reference to the MyClass
instance's heap space (which contains the information for the two
structs) on the stack. Again, all that goes on the stack in this case
is a simple reference (pointer) to the information on the heap.

As I said: structs act exactly like ints, doubles, floats, or decimals.
When passed as arguments to methods they are copied onto the stack.
When returned from methods, they are returned on the stack. When you
have local variables of a "struct" type, space for the entire struct's
information is allocated on the stack. When you assign them from one
variable to another, they are copied.

When a struct forms part of the information (the "state") for a class
instance, space for that struct is allocated on the heap along with
(and in the same memory as) the ints, doubles, and decimals that make
up the rest of the class's state information.

If you can understand how basic types like ints and decimals are
treated by the compiler and the CLR, then you understand how structs
are treated: exactly the same.
 
B

BravesCharm

What I think is weird is if you have a class field int and a class
field object and if you set object; now if you set the object to the
value of int it will box.

Example

public class NewTest
{
public NewTest(int x)
{
g = x;
//will box even tough they're both on the heap.
obj = g;
}

int g = 0;
object obj = null;
}
 
J

Jon Skeet [C# MVP]

Willy Denoyette said:
Agreed, just one small remark though, The article states "Every static
variable is stored on the heap", this is not completely correct if Jon here
meant the GC heap.
Static variables are not stored on the GC heap, but they live on a private,
per application domain heap, more precisely, on the "High Frequency heap"
within the loader heap. So, if you ever wonder where the PairOfInts static
counter variable lives, well it's on the "High Frequency Heap".

Righto - I'll amend the article when I get some time.
 
B

Bruce Wood

There are two reasons why you couldn't just grab a reference to the int
g and stuff that reference into "obj" and call it a day.

First, objects have more associated with them than just their data. In
my example above I didn't mention that allocating space for an object
on the heap also allocates other stuff that goes along with it. At the
very least, .NET allocates space for some sort of marker (probably a
pointer) that indicates what type of object the heap-allocated data
belongs to. Remember that at run time an object knows what type it is
(and never forgets that). Even if you do this:

ArrayList list = new ArrayList();
object obj = list;

the variable "obj" contains a reference that points into the heap to
object data that "knows" that it is an ArrayList. The only way it can
"know" that is to have some hidden data stored on the heap along with
the members you declared... hidden data that indicates what kind of
object it is. (There is also at least a vtable, and probably other
junk. Suffice to say that the member data isn't all there is.)

The int g, as part of NewTest, _is_ stored on the heap, but it doesn't
have all of that surrounding object information stored with it. It's
just 32 bits of integer data. When you assign it to "obj", you want to
"cut it loose" and have it live on its own outside the confines of its
declaring class instance. So, it needs to be boxed, which involves more
than just copying the 32 bits into some other heap location: it needs
additional information about what kind of object it is (an Int32).

Second, .NET has to work this way in order to maintain security and
code sanity. Think of what would happen if it didn't.

The whole point of having private members like g (well, you didn't
declare it private, but you should have) is to _encapsulate_ object
state so that the only way you can monkey with the value of a member
like g is to call a property or method of NewTest. So, you don't want
to be able to do things that break encapsulation. At least, you don't
want to be able to do things that unexpectedly break encapsulation.

Now, let's change .NET's semantics so that g doesn't get boxed. As I
noted above, there is another reason why that's impossible, but let's
ignore that for the moment. Now, in our theoretical CLR, when you say

object obj = g;

you just put a reference to g in "obj", and leave g where it was. Now,
let's say, you return "obj" from some property of NewTest... you hand
it off to the outside world.

Now you have a problem: you've toasted your encapsulation of "g". Now
anyone who has their mitts on a copy of that reference can modify "g"
and there's nothing you can do about it, there is no way to react to
it, and therefore no way to guarantee that your internal state is
self-consistent. As a NewTest object, your ability to control your
internal state and guarantee its vailidity has just been compromised.
Nasty.

This leads right back to C/C++ pointers, and all of the problems that
come with them.

Yes, if g were an ArrayList instead of an int, you could return a
reference to it and you run into a similar problem, but not the same
problem. Your caller can interact with the instance to which you
returned a reference and change _its_ state, but your caller still
can't change the reference you're holding and make it point to another
object.

Basically, copying on a box or unbox had the nice side-effect of
maintaining guarantees about who can do what to your class's members.
As I noted in the first part of this post, the CLR really doesn't have
any choice when it comes to copying on box / unbox. However, even if it
did have a choice, I would still want it to act the way it does now; a
change in behaviour would lead us back to annoying pointer problems.
 
B

Bruce Wood

(There is also at least a vtable, and probably other junk. Suffice to say that the member data isn't all there is.)

OK... that was stupid of me. The vtable is part of the class
definition. There's no need to have a separate vtable for each instance
of a class, so there is probably only one vtable per class stored
somewhere. Every instance of a class contains a pointer back to that
class's shared information, of which the vtable would logically be a
part.

Nonetheless, there must at least be some marker in the instance's
allocated heap space saying what kind of object it is, so that you can
get back to the global class information and the vtable.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top