0

For performance concern, I would like to access some attributes of an existing c++ struct like an array. Here is the type of structure I have:

struct MyStruct {
  Class1 c1;
  Class2 c2;
  MyClass myFirstAttribute, mySecondAttribute, /* ... */, myLastAttribute;
  Class3 c3;
  Class4 c4;
};

My goal would be to access the attributes of type MyClass as if they were an array such as:

struct MyStruct {
  Class1 c1;
  Class2 c2;
  MyClass myArray[20];
  Class3 c3;
  Class4 c4;
};

The class MyClass only contains 1 member (a double). So far, I wrote the following function and it seems to work, but I am wondering if I am not just lucky that the attributes are aligned as expected:

MyClass& accessElement(struct MyStruct &s, int index)
{
  MyClass *myArray = &s.myFirstAttribute;
  return myArray[index];
}

Reason

Please note that this is only temporary, I know it is better to directly use an array but it needs quite a few changes, but I need the change to be transparent as I don't manage all the code using this struct. Also, the reason behind the change is for performance as the function was previously implemented using a switch statement, and compiled as a if - then - else statement. I am compiling using gcc 4.3 with -std=c++98 and -O2 options among others.

Bonus

I also tried several other tricks, but it didn't work as I am playing with a very big and complicated code, such as:

  • Add the array as an attribute and change the attributes to references pointing to the the corresponding index of the array. This didn't work as it needs the copy constructor somewhere in the code and I needed to implement it, which is very fastidious (the struct is much more complicated).
  • Use a define macro to automatically replace all strings with the name of the attributes I want to replace by the corresponding array with index (see below). This didn't work as some variables in another part of the code have the same name than the attributes.

Using define:

#define myFirstAttribute myArray[0]
#define mySecondAttribute myArray[1]
#define myLastAttribute myArray[20]

Qestions

Any other ideas? Or is there any way I could make my hack safer to ensure it compiles as expected?

Edit

As suggested in this post (thank you @Thomas Matthews for the link), a lookup table would be better, however you pay the cost of the indirection (same as virtual functions I think). I am wondering if something like that would be legit:

struct MyStruct {
  Class1 c1;
  Class2 c2;

  union {
    struct {
      MyClass myFirstAttribute, mySecondAttribute, /* ... */, myLastAttribute;
    };
    MyClass myArray[];
  };
  Class3 c3;
  Class4 c4;
};

This seems to work, and is not suggested in the other post. Do I need to pack the anonymous struct? Any suggestion?

Community
  • 1
  • 1
Nicop
  • 314
  • 1
  • 6
  • Whay can't you use an array as posted in your example? – jpo38 Jan 20 '16 at 22:04
  • 2
    You could add an `operator[]` overload with a switch statement – M.M Jan 20 '16 at 22:08
  • Undefined behavior, of course. – SergeyA Jan 20 '16 at 22:10
  • 1
    This would seem to violate the strict aliasing rule. Perhaps you are trying to achieve something along the lines of `union`. – paddy Jan 20 '16 at 22:13
  • @M.M: Operator[] with a switch statement would not fix my performance issue. – Nicop Jan 20 '16 at 22:41
  • @SergeyA: Is there any way to make is defined? – Nicop Jan 20 '16 at 22:41
  • @paddy: Good point for the strict aliasing rule. Union is a good idea, but I am not sure about how to only do it on part of my struct unless I do it on all the struct and put my attributes at the beginning, but this is unsafe. Any suggestion? – Nicop Jan 20 '16 at 22:41
  • @Nicop I'm having trouble seeing where you're coming from. Your function `accessElement` is obviously slower than accessing the individual members by name. I am assuming you wrote it for convenience rather than performance, so you can iterate over the members in a loop for example. – M.M Jan 20 '16 at 23:05
  • @M.M I need to access randomly one of the attributes based on an enum passed in input. This function is called a lot of times and the value of the index is roughly random. – Nicop Jan 20 '16 at 23:08
  • A switch statement sounds like an ideal solution then, I'm not sure what makes you think that would perform worse than your "improvement" . Perhaps you could benchmark your code with both options. – M.M Jan 20 '16 at 23:15
  • @M.M I already profiled the function using callgrind. With 6 attributes and a switch statement, lookup takes between 400 and 450 instructions over 22 calls with random values (cannot be optimized at compile time). With an array (using my hack), it drops to between 100 and 120. All of that using gcc 4.3 and -O2 flag. Edit: The number of instructions is in total over the 22 calls, so around 20 instructions per call for the switch and 5 for the array. The real function also contains an if statement (the struct is passed as a pointer, not a reference). – Nicop Jan 20 '16 at 23:18
  • That seems a bit fishy, maybe worth investigating what happened. – M.M Jan 20 '16 at 23:59
  • Note that the union option is not supported by ISO C++ (although neither is your pointer hack). It's still relying on compiler-specific behaviour. – M.M Jan 20 '16 at 23:59

0 Answers0