I think the Component pointer in MoleculeInterface and derivatives is a bad design choice.
Here first some clarification on what I believe the pointer does:
It points to elements of some sort of database of components (retrieved via _simulation.getEnsemble()->getComponents()) stored in the Simulation singleton, which is most probably established once in the during init, and remains unchanged throughout the simulation.
Why is it bad?
In short, it hurts the C++ OCP and SRP principle. In detail:
- I noticed this, while trying to serialize a molecule's data. Needless to say, a pointer is not serializeable.
- As the database seems to be fixed, and organized as a std::vector (at least thats what getComponents() returns), it makes no sense to store a pointer. Just as e.g. ASCIIWriter class does, the index into the components data base is sufficient to fully describe the necessary information.
- I presume the choice for a pointer (over an index) was performance related. In a std::vector passing the index to the database and retrieving the appropriate component breaks down to a single addition, and therefore is negligible even if done very often in the tightest compute loop.
- Even worse, the ID that is serialized by e.g. writeBinary() method in MoleculeInterface is different from the index stored internally (off by one, cf. line 458 in FullMolecule.cpp). I believe this is because the (externally defined) database counts 1 based, and the std::vector counts 0-based. This essentially means that every code dealing with components needs to be aware of this shift and has to implement it, even though this clearly should be the responsibility of the database.
- If the database does not exist, any code using molecules is at risk of breaking. This essentially makes it impossible to write a unit test for deserialize()-ing (without building at least a dummy database in the Simulation singleton), as that method attempts to convert the serialized component id back into a pointer. Of course, a dummy database can be built, but then its not a unit test, but depends on that database.
How to fix
Instead of storing a pointer, store an index.
The pointer would need to be substituted for a call to the database passing the index, returning the actual Component object (or a pointer to that), which can be stored in the instance, e.g. during contruction.
This would decouple the database, as the molecule is defined by its component id, regardless of how the database evaluates this. The responsibility of processing the id correctly would fall to the database implementation.
As the class-internal usage of the component pointer in FullMolecule.cpp is restricted to _component->ID(), other solutions might make sense. MoleculeRMM.cpp does not use it at all.
The interface additionally uses only _component->m(), so other solutions, omitting the pointer entirely, might be possible.
However, I did not think this through, might also be very hard to eliminate it completely.
Conclusion
I can see, that if that pointer is used in many different places and possibly indirectly, refactoring this may not be an option, but this is a mean trap, not to say a terrible design choice.
I guess the code is as it is for 'historical' reasons, but it would be a good idea to change that.
P.S.: Don't be mad for my little rant, if you don't want to change it, that's fine, but there won't be a unit test for deserializing :). Just close the issue if you think this is not worth your time.