If you want to help your caches, another technique that can be helpful is data-oriented design. Often, it's a good idea to store members used more often close to each other in memory. Colder data can often be placed in another struct and just be connected with the hotter data by an ID or a pointer.
Sometimes, instead of the more commonly spotted arrays of objects, using objects of arrays can yield better performance. Instead of writing your code in an object-oriented manner, split your object's data member across a few arrays, each containing data for multiple objects. In other words, take the following code:
struct Widget { Foo foo; Bar bar; Baz baz; }; auto widgets = std::vector<Widget>{};
And consider replacing it with the following:
struct Widgets { std::vector<Foo> foos; std::vector<Bar> bars; std::vector<Baz> bazs; };
This way, when processing a specific set of data points against some...