I am creating a geometry library in C# and I will need the following immutable types:
Vector2f
(2float
s - 8 bytes)Vector2d
(2double
s - 16 bytes)Vector3f
(3float
s - 12 bytes)Vector3d
(3double开发者_JAVA百科
s - 24 bytes)Vector4f
(4float
s - 16 bytes)Vector4d
(4double
s - 32 bytes)
I am trying to determine whether to make them structs or classes. MSDN suggests only using a struct if the size if going to be no greater than 16 bytes. That reference seems to be from 2005. Is 16 bytes still the max suggested size?
I am sure that using structs for the float
vectors would be more efficient than using a class, but what should I do about the double
vectors? Should I make them structs also to be consistent, or should I make them classes?
Updated: Looks like the everyone agrees they should be structs. Thanks for the great answers.
Microsoft's XNA Framework uses structures for its Vector2/3/4 data types. These contain fields of type float
. I don't see anything wrong with doing the same; using fields of type double
shouldn't make a big difference.
I would generally make types like these structs. Structs are more likely to be placed on the stack, and if you use arrays with them, you can get much nicer peformance than if, say, you were to use a List<> of objects. As long as you stay away from operations which will cause your vector classes to be boxed, the struct is the generally going to be the higher performance way to go.
Immutable structs is a good choice. The size recommendation on MSDN is the weakest, 32 bytes is not really big.
The main argument would be that Vectors are used like simple (numerical) types and an implementation as value type is most appropriate.
A good parallel are the new Complex and BigInteger structs in dotNet 4
Structs, definitely. Why? Well, it's part feeling I guess, a vector just feels and behaves like a value.
Rico Mariani here gives some reasons why value types were chosen for certain types for an API (I don't think it's XNA he's talking about).
And while efficiency is a factor here, I don't think it's about garbage collection, but more about data density like Rico says. Say you also have a Vertex
type, that contains two Vector3
s: a Vector3
for the normal and a Vector3
for the world co-ordinates. If you made those types classes, then having an array with 100 Vertex
elements, would consist of:
- 100 * 8 bytes (8 bytes is I believe the overhead of a class in memory, 4 bytes for the type header and 4 bytes for something else, a GC handle?)
- 100 * 4 bytes (for the pointers in the array to the
Vertex
elements) - 200 * 4 bytes (for the pointers from each
Vertex
to the twoVector3
elements) - 200 * 8 bytes (for the 8 byte overhead that you pay for making
Vector3
a class) - 200 * 12 bytes (for the actual payload of 3
float
perVector3
)
6000 bytes (on a 32-bit system).
As a value type, it's simply 200 * 12 bytes = 2400 bytes. So much more efficient space-wise not to mention a lower level of indirection when reading the array.
But taking up a lot of space doesn't necessarily make it slow, using a value type incorrectly can be slower than making it a class, as I have found out. You definitely want to pass them by ref
as much as possible, avoid copying them, but this doesn't go for all operations, so measure. I think I remember calculating the dot-product was slower when passing by ref
, perhaps because it somehow prevented in-lining by making the IL larger. But don't take my word for it, just measure.
In my opinion I would go with structs for this, since they would be allocated on the stack most times this would reduce the pressure on the GC so your application should run smoother.
One tip, your methods that opperate on the structs should probably take the arguments as ref and out arguments, this will reduce the amount of copying of the data that takes place when passing and returning structs.
We recently switched some maths types (vec3, vec4, matrices etc.) over to use structs instead of classes and, as well as being slightly quicker in benchmarks, it also reduced the GC pressure (we had hundreds of megabytes of Vec3 allocations over a relatively short period of time, discovered via the CLR profiler).
It's interesting to note that the Xna implementation of Vectors & Matrices is done using structs. You can always pass by reference where appropriate if you're concerned about performance, too.
I assume you're worried about perf?
If they're immutable, they should be behaviorally identical. Just go with one, and if it turns out that there's a perf issue, switch it later on.
If you're targetting .NET CE at all, you should probably consider using structs as the GC isn't as efficient as the full .NET implementation.
Structs are (usually) stored on the stack, which might make them more efficient, but probably not enough to make a noticeable difference.
http://www.c-sharpcorner.com/UploadFile/rmcochran/csharp_memory01122006130034PM/csharp_memory.aspx?ArticleID=9adb0e3c-b3f6-40b5-98b5-413b6d348b91
精彩评论