Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does it make sense to define a struct with a reference type member?

Is there any sense in defining a struct with a reference type member (and not defining it as a class)? For example, to define this struct:

public struct SomeStruct
{
    string name;
    Int32  place;
}

I asking because I know that a struct is a value type, and to define in it some reference type does not make any sense.

Am I right? Can someone explain this?

like image 507
Yanshof Avatar asked Apr 11 '11 11:04

Yanshof


People also ask

Can a struct contain a reference type?

Yes, it is possible, and yes, it is usually a bad practice. If you look at the . NET framework itself, you'll see virtually all structs contain primitive value types alone.

Is struct a reference data type?

Structs are value types, while classes are reference types, and the runtime deals with the two in different ways. When a value-type instance is created, a single space in memory is allocated to store the value. Primitive types such as int, float, bool and char are also value types, and work in the same way.

Do structs need to be passed by reference?

A struct can be either passed/returned by value or passed/returned by reference (via a pointer) in C. The general consensus seems to be that the former can be applied to small structs without penalty in most cases.

Is struct value type or reference type?

However, unlike classes, structs are value types and do not require heap allocation. A variable of a struct type directly contains the data of the struct , whereas a variable of a class type contains a reference to the data, the latter known as an object.

Why do we want to pass struct objects by reference?

Passing by reference uses a pointer to access the structure arguments. If the function writes to an element of the input structure, it overwrites the input value. Passing by value makes a copy of the input or output structure argument. To reduce memory usage and execution time, use pass by reference.

Where should I define a struct?

If the struct is to be used by other compilation units (. c files) , place it in the header file so you can include that header file wherever it is needed. If the struct is only used in one compilation unit (. c file), you place it in that .


4 Answers

Nine times out of ten, you should be creating a class rather than a structure in the first place. Structures and classes have very different semantics in C#, compared to what you might find in C++, for example. Most programmers who use a structure should have used a class, making questions like this one quite frankly irrelevant.

Here are some quick rules about when you should choose a structure over a class:

  1. Never.
    ...Oh, you're still reading? You're persistent. Okay, fine.
  2. When you have an explicit need for value-type semantics, as opposed to reference type semantics.
  3. When you have a very small type (the rule of thumb is a memory footprint less than 16 bytes).
  4. When objects represented by your struct will be short-lived and immutable (won't change).
  5. And occasionally, for interop purposes with native code that uses structures.

But if you've made an informed decision and are truly confident that you do, in fact, need a structure rather than a class, you need to revisit point number 2 and understand what value type semantics are. Jon Skeet's article here should go a long way towards clarifying the distinction.

Once you've done that, you should understand why defining a reference type inside of a value type (struct) is not a problem. Reference types are like pointers. The field inside of the structure doesn't store the actual type; rather, it stores a pointer (or a reference) to that type. There's nothing contradictory or wrong about declaring a struct with a field containing a reference type. It will neither "slow the object" nor will it "call GC", the two concerns you express in a comment.

like image 76
Cody Gray Avatar answered Nov 08 '22 20:11

Cody Gray


Declaring a field of a reference type means there needs to be space to hold the value of the reference that is pointing to the target object. Thus it makes perfect sense to have such fields in structs.

like image 4
Ondrej Tucny Avatar answered Nov 08 '22 20:11

Ondrej Tucny


In general, a struct should only contain a public and/or mutable field of a reference type if one of the following conditions applies:

  1. All instances of that type may be regarded as inherently immutable (as is the case of `string`)
  2. The semantics of the struct clearly imply that the field identifies the object to which it refers, rather than encapsulating its state, and that the state of the object referred to by the field is not considered part of the struct. For example, in a KeyValuePair<string, Form>, one would expect the `Value` to identify a form instance; moving the form around the screen would change `Value.Bounds`, but would not be considered to change `Value` (which would continue to refer to the same form, regardless of its on-screen location)

If neither condition applies, it may be appropriate for a structure to hold a field of a reference type provided all of the following conditions apply:

  1. The field never holds a reference to any mutable object which the struct did not itself create.
  2. The reference must never be exposed, nor ever have been exposed, to any code that might in future mutate the object it refers to.
  3. All mutations that are ever going to be done on the object to which the field is going to refer must be performed before a reference is stored in the field.

In other words, an object reference which is used to encapsulate the state of an object (as opposed to merely identifying it) should only be stored in a struct field if there is no execution path via which the object to which it refers might be modified.

like image 3
supercat Avatar answered Nov 08 '22 21:11

supercat


I'm interested to hear what more experienced coders have to say about the pros and cons of this, but my understanding is that, as a value type, a variable of type SomeStruct would be allocated from the stack, but would contain a reference to the location on the heap containing the string.

like image 2
Andrew Cooper Avatar answered Nov 08 '22 20:11

Andrew Cooper