A struct
may or may not be allocated on the stack. Reference types can never be allocated on the stack; they are always allocated on the heap.
From the Standard (ISO 23270), § 8.8:
8.8 Structs
The list of similarities between classes and structs is long—structs can implement
interfaces, and can have the same kinds of members as classes. Structs differ from
classes in several important ways, however: structs are value types rather than
reference types, and inheritance is not supported for structs. Struct values
are stored “on the stack” or “in-line”. Careful programmers can sometimes enhance
performance through judicious use of structs.
For example, the use of a struct rather than a class for a Point can make a large
difference in the number of memory allocations performed at run time. The program
below creates and initializes an array of 100 points.
With Point
implemented as a class, 101 separate objects are instantiated—one for the
array and one each for the 100 elements.
class Point
{
public int x, y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
class Test
{
static void Main()
{
Point[] points = new Point[100];
for (int i = 0; i < 100; i++)
{
points[i] = new Point(i, i*i);
}
}
If Point
is instead implemented as a struct, as in
struct Point
{
public int x, y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
only one object is instantiated—the one for the array. The Point instances are
allocated in-line within the array. This optimization can be misused. Using structs
instead of classes can also make an application run slower or take up more memory,
as passing a struct instance by value causes a copy of that struct to be created.
So the answer is "Maybe".
For your example, wrapping an array (a reference type) within a struct
(a value type), doesn't mean anything: that array is still allocated on the heap.
If however, you change your class EdgeData
to a struct, it can be (but may not be) allocated in-line within the array. So if your EdgeData
class is, for instance, 16 bytes in size, and you create and populate an EdgeData[]
of 100 entries, you are actually allocating 1 array instance (with a backing store sized to hold 100 object references, and 100 individual instances of your EdgeData
class.
If EdgeData
is a struct, you allocate 1 array with a backing store sized to hold 100 EdgeData
instances (in this case, 1600 bytes, since our hypothetical EdgeData
struct is 16 bytes in size.)
Iterating over the class version of the array, especially if the array is very large, may cause paging, since you are probably losing locality of reference as you jump all over the heap to hit the individual EdgeData
instances.
Iteration over the struct
version of the array preserves locality of reference, since the EdgeData
instances are in-line.