Struct constructors bad?

snarfblam

Ultimate Contributor
Joined
Jun 10, 2003
Messages
2,097
Location
USA
Another chapter in my never ending quest to micro-optimize. Anyone up for a long read?

I was thinking about structs. I make a lot of use of them, because I hate to create garbage collected objects when they aren't neccessary. I prefer to let the memory be reclaimed when they go out of scope and save the memory used to manage the object. (Of course, I use classes when they are appropriate, too.)

But I was wondering about using struct constructors. When you use the StructInstance = New Struct syntax, I would image that a new struct is allocated on the stack, initialized to default values, the constructor is called, then the newly allocated struct is assigned to the original. If you were to create a static intialization method, however, you could avoid the creation and intialization of a new struct on the stack.

I reasoned, however, that the inefficiencies of using a constructor to assign a value to a struct would be optimized out. Of course, I had to see for myself. I coded a constructor, and disassembled it, and discovered that indeed, a new struct is allocatated, initialized to default values, the constructor is called (we are essentially initializing twice, here), and then is assigned back to the original struct. I did this with a release build because this is the build that the end-user will be using.

I created a test struct with a constructor and a static method both of which could be used to initialize an already allocated struct.

Visual Basic:
Public Structure TestStruct
    'Members 1 through 5
    Dim M1, M2, M3, M4, M5 As Single
 
    'Using constructor to initialize
    Public Sub New(ByVal A As Single, ByVal B As Single, _
      ByVal C As Single, ByVal D As Single, ByVal E As Single)
        M1 = A
        M2 = B
        M3 = C
        M4 = D
        M5 = E
    End Sub
 
    'Using shared method to initialize
    Shared Sub StaticInit(ByRef Struct As TestStruct, ByVal A As Single, _
      ByVal B As Single, ByVal C As Single, ByVal D As Single, ByVal E As Single)
        Struct.M1 = A
        Struct.M2 = B
        Struct.M3 = C
        Struct.M4 = D
        Struct.M5 = E
    End Sub
End Structure

And of course we have a function to test these two methods:
Visual Basic:
    Sub Test()
        'Struct to be initialized
        Dim Struct As TestStruct
        'Times to init struct
        Dim Times As Integer = 10000000
 
        'Test static function
        Dim Start As Integer = System.Environment.TickCount
        For i As Integer = 0 To Times
            TestStruct.StaticInit(Struct, 1, 2, 3, 4, 5)
        Next
        Dim FirstTime As Integer = System.Environment.TickCount - Start
 
        'Test constructor
        Start = System.Environment.TickCount
        For i As Integer = 0 To Times
            Struct = New TestStruct(1, 2, 3, 4, 5)
        Next
        Dim SecondTime As Integer = System.Environment.TickCount - Start
 
        'Display results
        MessageBox.Show(FirstTime.ToString & " " & SecondTime.ToString)
    End Sub
Well, I was dissapointed to see that the constructor, the easier and more intuitive method, ran considerably slower than the static intialization function. The results for six runs were as follows (timed in milliseconds, .ctor = constructor):
Code:
Run  .ctor Static | Run  .ctor Static
1    551   160    | 4    521   190
2    531   160    | 5    521   190
3    541   160    | 6    521   190
In the last three runs, I reversed the order of the loops, testing the constructor first and then the static method.

This also begs the question as to whether one method or the other is faster when initializing a struct when it is allocated, i.e. Dim X As New Struct() vs. Dim X As Struct : Struct.Init(X).

Using a similar test, these are the results that I got, again, switching the order of the tests on the second set of runs:
Code:
Run  .ctor Static | Run  .ctor Static
1    360   170    | 4    441   170
2    351   160    | 5    351   170
3    350   170    | 6    361   170
It looked a little better for the constructor in the second test, but still disappointing. Of course, you're wondering when you will need to initialize ten million structs, and of course the answer is never. But maybe knowing that constructors aren't particularly efficient can help you sort out a bottle-neck issue someday, or give your Direct3D game a speed boost when you create hundreds or thousands of vertices.
 
Back
Top