I hope it's ok to answer my own question.
I believe I have found the optimal (without overcomplicating the problem) data structure for my problem. There was at least minor idiocy on my part for not recognising this earlier. The data doesn't need to be accessed by (x,y,z) but instead by (x, y, range of z (say 0 - 3)). This give a C++ struct as follows:
struct node {
struct node *next;
int zGroup;
int z;
50 bytes of misc data };
I can then address this through a 3D dynamic array (vectors):
vector< vector < vector < node* > > > Data;
Any given Data[x][y][zGroup]
points to the first element of a linked list, the entirety of which is needed every time one element of it is needed. No value of this array is NULL, every one contains a linked-list of at least one element.
The third dimension of the array - the zGroup has jagged dimensions, but with dynamic arrays this isn't an issue. Given the data and computations being performed on it, I know that the max x and y values are set when the file is read and do not change, neither does the number of z groups on any given (x,y) line, the actual z-values of nodes may change, but they will remain inside the same z-groups, giving a constant-sized, fully populated array.
With the way that the file is structured it is also easy enough to page it in and out of memory if I am brought to do this with much larger data sets.
I think you might be getting stuck trying to make your class hierarchy fit a real-world taxonomy, and that's not always the best approach.
First of all, objects are almost always created by some sort of factory in this situation. You call a probe
function that returns a list of all Widgets
connected to your system, already instantiated. Then you can configure it.
The model I see most often for a hardware device is a data structure of features. Take a mouse, for example. They all have at least two buttons and at least two axes, but some have much more. Rather than have a base Mouse
class with derived classes like ThreeButtonWithScroll
, they each have an Axes
collection and a Buttons
collection. The user of the class isn't allowed to add or remove an axis or button, but he can set properties on each.
Say you had some sort of weird mouse without any buttons. Its Buttons
collection would just be empty, and therefore unconfigurable. You're not exposing any interfaces that aren't allowed to be used.
If your list of features is so huge that you would be only using a small portion of them on any given device, then you could create an array of Features
in your Widget
class. Where a Feature
could be the unique things about some mice like Vibration
or BacklightColor
. These can also be relatively generic, like BooleanFeature("Vibration", disabled, callback)
.
Best Answer
Most compilers will implement references as pointers. So the deep answer to your question is that there will be absolutely no difference in terms of performance between the two. (Doesn't change aliasing analysis either as far as I know.)
If you want to be 100% sure of that statement, inspect your compiler's output.
Compiled with
clang++ -O2
, saving the assembly:You can try that with a large struct or an enormously complex struct - doesn't matter, all you're passing in to the function is a pointer.
That being said, there are semantic differences between the two. The most important one being that, as long as your program is free of undefined behavior, the overload that takes a reference is guaranteed to get a reference to a valid, live object. The pointer overload isn't.
Also assigning to
s
in these two examples has completely different meanings. It would replace the pointer in the first function (i.e. whatever it pointed to remains unchanged, but becomes unreachable from within that function; caller unaffected by the assignment).In the second, it would call the appropriate assignment operator en the object passed in (effect visible from the caller).
So your choice shouldn't be made on a potential performance difference (there will generally be none), but on semantics. What you need the function to be able to do, and how you should be able to call it, will dictate what overload(s) you need to provide.