Structures versus Classes

I am going to create 100,000 objects in code. They are small, with only 2 or 3 properties. I will put them in a general list, and when they are, I will loop them and hold the value of a and possibly update the value of b .

Is it faster / better to create these objects as a class or as a struct?

EDIT

but. Properties are value types (except for the string I think?)

b. They may (we are not sure yet) have a validation method

EDIT 2

I was wondering: are there objects on the heap and the stack handled equally by the garbage collector, or does it work differently?

+81
c # struct
Oct. 15 '10 at 13:37
source share
11 answers

Is it faster to create these objects as a class or as a struct?

You are the only one who can determine the answer to this question. Try this in two ways: measure a meaningful, user-oriented, appropriate performance metric, and then you will find out if this change has a meaningful effect on real users in the respective scenarios.

Structures consume less heap memory (because they are smaller and easier to compact, and not because they are "on the stack"). But they copy more than a copy. I don't know what your performance indicators are for memory usage or speed; there is a compromise, and you are the one who knows what it is.

Is it better to create these objects as a class or as a struct?

Maybe a class, maybe a structure. Typically thumb: If an object:
1. Small
2. Logically immutable value
3. There are many of them. Then I would think about creating a structure. Otherwise, I would stick with a reference type.

If you need to mutate any field of the structure, it is usually better to build a constructor that will return the whole new structure with the given field correctly. It may be a little slower (measure it!), But logically it is much easier to reason.

Are objects on the heap and stack equally handled by the garbage collector?

No , they do not match, since the objects on the stack are the roots of the collection. The garbage collector does not need to ever ask: "Is this a living thing on the stack?" because the answer to this question is always "Yes, it is on the stack." (Now you cannot rely on this to keep the object alive, because the stack is an implementation detail. Jitter is allowed to introduce an optimization that, say, registers what is usually the value of the stack, and then never on the stack so the GC doesn't know that it is still alive. A registered object can collect its descendants aggressively as soon as the register held on it is not read again.)

But the garbage collector must consider objects on the stack as living, just as it relates to any object that is known to be alive as alive. An object on the stack can refer to objects allocated by the heap that need to be kept alive, so the GC must process the objects of the stack, such as live objects allocated by the heap, to define a live set. But, obviously, they are not considered “living objects” to compact the heap, because they are not in the heap in the first place.

It is clear?

+123
Oct 15 2018-10-15
source share
— -

Sometimes with a struct you don’t need to call the new () constructor and directly assign fields that make it much faster than usual.

Example:

 Value[] list = new Value[N]; for (int i = 0; i < N; i++) { list[i].id = i; list[i].is_valid = true; } 

about 2 to 3 times faster than

 Value[] list = new Value[N]; for (int i = 0; i < N; i++) { list[i] = new Value(i, true); } 

where Value is a struct with two fields (id and is_valid).

On the other hand, items must be moved or selected value types, anything that copies will slow you down. To get an exact answer, I suspect that you need to profile your code and check it.

+22
Oct 15 2018-10-15
source share

The list will return a copy of the structure. To update it, you will need to remove it from the list and again add the creation of a new copy with new values ​​and assignment to its list index.

Therefore, it is better to use classes.

Related reading: Why are volatile structures “evil”?

+18
Oct. 15 2018-10-15
source share

Structures may seem like classes, but there are important differences that you should be aware of. First of all, classes are reference types, and structures are value types. Using structures, you can create objects that behave as built-in types and take advantage of them.

When you call the New operator in a class, it will be allocated on the heap. However, when you instantiate the structure, it is created on the stack. This will give a performance boost. In addition, you will not deal with references to an instance of the structure, as with classes. You will work directly with the struct instance. Because of this, when passing a structure to a method, it is passed by value, and not as a reference.

More details here:

http://msdn.microsoft.com/en-us/library/aa288471(VS.71).aspx

+6
Oct. 15 2018-10-15
source share

Arrays of structures are represented on the heap in a continuous block of memory, while an array of objects is represented as a continuous block of links with the actual objects in another place in the heap, which requires memory for both objects and their reference to arrays.

In this case, when you put them in List<> (and a List<> supported on the array), it would be more efficient to use memory in memory.

(Beware, however, that large arrays will find their way into a bunch of large objects, where, if their lifespan is long, can negatively affect process memory management. Remember also that memory is not the only consideration.)

+6
Oct. 15 2018-10-15
source share

If they have semantics of values, you should probably use struct. If they have reference semantics, then you should probably use a class. There are exceptions that mostly tend to create a class, even if there is a semantics of values, but start from there.

As in the second edit, the GC deals only with the heap, but there is much more heap space than the stack space, so placing things on the stack is not always a victory. In addition, the list of struct types and the list of class types will be on the heap anyway, so it doesn't matter in this case.

Edit:

I begin to consider the term evil harmful. In the end, creating a mutable class is a bad idea if it is not needed, and I would not rule out that I have ever used a mutable structure. This is a bad idea so often that it is almost always a bad idea, but basically it just does not coincide with semantic semantics, so it just does not make sense to use structure in this case.

There may be reasonable exceptions with private nested structures, where all uses of this structure are therefore limited to a very limited area. However, this is not applicable.

In fact, I think that “it mutates, so this is a bad indicator” is not much better than about heap and stack (which, at least, has some effect on performance, even if it is often distorted). “It mutates, so it’s likely it doesn’t make sense to consider it to have semantics of meanings, so it’s a bad structure” is a little different, but, importantly, I think.

+4
Oct. 15 2018-10-15
source share

The best solution is to measure, measure again, then measure a little more. There may be details of what you are doing that may simplify a simple and easy answer, such as “use structures” or “use classes”.

+3
Oct. 15 2018-10-15
source share

The structure in your heart is nothing but the aggregation of fields. In .NET it is possible that the structure “pretends” to be an object, and for each type of structure .NET implicitly determines the type of the heap object with the same fields and methods that, being the heap object, will behave like an object, a variable that contains a link to such a heap object (“boxed”) will demonstrate link semantics, but one that directly contains the structure is simply an aggregation of variables.

I think that most of the confusion between structures and classes stems from the fact that structures have two very different use cases that should have very different design principles, but MS recommendations don't distinguish between them. Sometimes a need arises for what behaves as an object; in this case, the MS recommendations are pretty reasonable, although the "16 byte limit" should be more like 24-32. Sometimes, however, aggregation of variables is necessary. The string used for this purpose should consist only of a combination of open fields and, possibly, an override of Equals , ToString and IEquatable(itsType).Equals . Structures that are used as clusters of fields are not objects and should not claim a role. In terms of structure, the value of the field should be no more or less than "the last thing written in this field." Any additional value must be determined by the client code.

For example, if the variable aggregation structure has the Minimum and Maximum members, the structure itself should not promise that Minimum <= Maximum . Code that receives such a structure as a parameter should behave as if it were passed to the individual Minimum and Maximum values. The requirement that Minimum does not exceed Maximum should be considered as a requirement that the Minimum parameter does not exceed the separately passed Maximum .

A useful example to consider is sometimes the existence of the ExposedHolder<T> class, defined as:

 class ExposedHolder<T> { public T Value; ExposedHolder() { } ExposedHolder(T val) { Value = T; } } 

If I have a List<ExposedHolder<someStruct>> , where someStruct is a variable aggregating structure, you can do things like myList[3].Value.someField += 7; , but providing myList[3].Value another code will give it the contents of Value , rather than giving it the ability to change it. In contrast, if you use a List<someStruct> , you must use var temp=myList[3]; temp.someField += 7; myList[3] = temp; var temp=myList[3]; temp.someField += 7; myList[3] = temp; . If you used the type of a mutable class, exposing the contents of myList[3] external code, you will need to copy all the fields to some other object. If you were to use an immutable class type or an object-style structure, you would need to create a new instance that was like myList[3] , except for someField , which was different, and then save that new instance in the list.

One more note. If you store a large number of similar things, it can be useful to store them in possibly nested arrays of structures, preferably to keep the size of each array between 1K and 64K or so. Arrays of structures are special because indexing provides a direct link to the structure inside, so you can say "a [12] .x = 5;". Although you can define objects of an array type, C # does not allow them to use this syntax with arrays.

+3
Oct. 15 2018-10-15
source share

From a C ++ point of view, I agree that this will change the properties of structs more slowly compared to the class. But I think that they will read faster due to the fact that the structure is allocated on the stack instead of the heap. Reading data from the heap requires more checks than from the stack.

+2
Oct. 15 2018-10-15
source share

Use classes.

About the general note. Why not update the value of b when you create them?

+1
Oct. 15 '10 at 13:40
source share

Well, if you go with the afterall structure, then get rid of the string and use a fixed char size or byte buffer.

This is a repeat: performance.

+1
Oct. 15 '10 at 17:31
source share



All Articles