Oh I see the confusion. Let me rephrase and be more clear what I was trying to say:
@Matias Goldberg: I got that. I didn't want to imply you recommended copy&paste programming. When you wrote "...rather than having to refactor everything or resort to copy-pasting the constructor into a reinit() function, then debug why reinit is failing (because you pasted more code than you should, or forgot to copy something).", in my opinion reinit() is a) just another form of two-stage initialization and b) can avoid code duplication just the same (it's not like reinit() would somehow force it).
When using the one-step, eventually something may pop up that requires a reinitialization that is inconsistent or hard to solve with the one-step initialization solution you've designed from the beginning. To solve that issue, you have three choices:
- Refactor everything so that you still end up using One-step init. The most elegant solution but requires time to refactor.
- Modify the affected part so it ends up as a two-step init. (for this/these particular case(s)). For example, first pass may contain immutable data, while second one would contain data that is supposed to be reinitialized. When it's time to reinit, just call the second pass' function. Much faster to code and still elegant.
- Copy / paste the constructor into a different function and use that function when you have to reinit as an exceptional case--> Avoid this, it's error prone.
I would still strongly prefer one-stage initialization in all 4 cases you listed. But instead of just criticizing your design, let me explain how I would have done it and you can criticize mine )
It's pretty much how my system already works ;)
Object reloading for memory & performance: I have a logical game object which maintains the persistent state (eg. class ScarySpider with int health, Item loot, int xp). Add AI, physics etc. via composition. This thing gets loaded and saved with a level and in savegames. With a client/server model, the server would only work with this logical game object. To actually render it, there is a class ScarySpiderPresenter which creates and maintains the visual and audible representation of the logical game object in the game's scene graph. If I wanted to reclaim memory this way, I'd destroy the ScarySpiderPresenter but leave the ScarySpider.
There will be a few (solvable) issues I ran to, for example the AI needs bounding box information for their calculations, which needs to be handled correctly during the composition or else they'll end up tied together. The Physics need to access the Animation data to extract motion, and so on..
Unfortunately in my case destroying ScarySpiderPresenter is hard (but not impossible) because the Graphics is manipulated from a different thread than Logic. However, I do have control free of what happens inside ScarySpiderPresenter though; but since I use Ogre I start being tied to what happens inside Ogre::Entity.
A trade off from using an existing tech rather than rolling my own or modifiying existing one. Unfortunately Ogre is not very multi-thread friendly and I don't have time to spend on it, but I've already submitted a proposal for 2.0. It would be very easy for me to implement those features but it takes time, and currently I'm commited into finishing my own project.
That's a very interesting method (and surprisingly simple, I like it). I'll take it into account! Thanks.
Reloading for in-place editing: Kill ScarySpiderPresenter, create ScarySpiderEditorPresenter. The latter could derive from the former or both could derive from a common base class as appropriate if there is shared functionality. This presenter could draw bounding boxes, overlay the AI's current patrol path / attack target or display scale and rotate widgets or whatever you like. Normal gameplay is not burdened with dragging the editor-specific state variables along as dead code.
Level reloading seems fine, there are hundreds of ways of doing it. Like I said that's the one that gets often most attention.