Is it really slower to use classes/structs?

Started by
9 comments, last by Raghar 15 years, 5 months ago
I read in a Java book (not sure at all if this applies to C++) that using classes and/or structs for simplistic stuff such as data types (explanation will follow) is much slower than using "hard values". For example: Having a wrapper class for Vector-based functionality in a game is very common, but should, according to the text I read, be slower than using hard values when calculating. Consider the following: I have a function in my Vector3 class called Normalize. This function is used quite often and normalizes the vector to a unit length of 1. Would this be slower than having three "regular" floats and passing them to a C-style Normalize function? i.e. void Vector3::Normalize() { ... } as opposed to void NormalizeVector3(float x, float y, float z) { ... } The book said that using a class/struct for simplistic stuff like this would create a lot of stuff on the stack, which would be slow (since you really don't go and create "data type" classes like the Vector3 with "new" every time you wish to use it). What say you? I am unsure of this and have no further clarifications. Does this apply to C++? If so, then I guess C-style code is a way to optimize an application.
Advertisement
Technically it is slower, but the difference is so small that you would need to do the operation thousands of times to notice a tiny speed increase. In the example you gave I'm not sure if there would even be a speed increase because you are still passing values (hopefully by reference) a function, which is just like having a class that has a normalize function.

In general, if done right, procedural programming is faster that object oriented programming BUT there is a reason so many languages support OOP: It speeds up production time, it's easier to find and fix errors (some might say it's less error prone to begin with and the code is easier to read. There are probably other reasons too.
It is entirely true!

In C++, using java classes to represent elementary data types, such as vectors, leads to some avoidable overhead. On the other hand, using C++ classes does not.

Just because Java and C++ both have something called a 'class' doesn't mean they are identical. Karl Marx had classes, too, and unlike C++ and/or java there were serious problems with inheritance.

Ultimately, using classes for vectors is faster (in terms of development time) than manipulating the coordinates by hand. This leaves more time for optimizing by hand the parts that really matter. Do you want to spend an additional hour improving your performance by half a millisecond on the loading screen, when that hour could be spent getting down your frame length from 12 to 10 milliseconds?

I'm not entirely sure what you mean with all this. Maybe it would help to quote the book.

Generally, "C-style code" is not a way to optimize an application. Neither in Java nor in C++.

As for "creating stuff on the stack", "NormalizeVector3" would put more stuff on the stack than "Vector3::Normalize". Also, "NormalizeVector3", won't work as you wrote it, because it has no way of returning the result...

Yeah, I am inclined to agree that OOP does indeed provide structure, but I do feel that OOP might also provide another "layer" to the computational side of things, which I am a little worried about.
For something like a vector class, you want to write everything in the header, as inline functions. Once inlined and otherwise optimized, a vector class should be no slower than writing out the math in place, as most vector operations aren't complicated enough to even warant a function call a good compiler wouldn't bother with one.

Other than that, there shouldn't be any inherent slowdown from one type of function over the other.
Though, when un-optimized:

vec.x = 5.0f;
vec.y = 6.0f;
vec.z = 7.0f;
vec.w = 8.0f;
vec = vec.normalize();

Might be slower than

vec = Normalize(1.0f, 2.0f, 3.0f, 4.0f);

but shouldn't be slower than

x = 1.0f;
y = 2.0f;
z = 3.0f;
w = 4.0f;
vec = Normalize(x,y,z,w);

BUT Optimized it shouldn't make any difference at all.
To give an example where it does matter: mobile Java applications (J2ME). Not only will a vector class have a negative impact on performance, it will also increase the file size of the application. Both are real issues on limited devices.

In C++ and on 'normal' platforms this isn't normally something to worry about.
These are all good points. I am glad to be able to get some input from more people on this. Thanks!
One important feature of C++ classes is that the compiler is allowed to cheat as much as it likes. It doesn't *have* to create the class at all, if it can inline all access to it. Large chunks of the standard library, and especially Boost, make use of this. Template metaprogramming might create hundreds and hundreds of classes which get inlined by the compiler, so the resulting code is just as efficient as if you'd just stuck all the code in one function.

Of course, this relies on the compiler to optimize aggressively, but in C++ that's both legal and fairly common.
The Java spec builds a lot of things into classes that are not present in C++ classes by default. They are reference objects, meaning that you never actually have a variable that directly stores the class data, but instead your variable holds a magical pointer-like thing to that data (it behaves like a C++ pointer in that it can be null and can be reseated; but it behaves like a C++ reference in that operating upon it - except for assignment - actually operates upon the pointed-at/referred-to data, and in that it doesn't support pointer arithmetic and can't point at garbage). The data structure itself is always part of a virtual inheritance structure (everything implicitly extends java.lang.Object if it doesn't explicitly extend anything else), and therefore includes a vtable pointer. It may also track a reference count (for garbage collection) and a monitor (any object in the system can be used as a lock for thread synchronization). It might also be indirected a second time (ISTR some implementations did this for some reason that I don't recall). To get any of this in C++, you have to request it explicitly (by implementing reference-count garbage collection, defining a base Object type for everything and giving it a virtual destructor and an int-sized field that can be set to a thread ID to make it act as a lock).

This topic is closed to new replies.

Advertisement