Second of all I should say that the people I was discussing this with are Very Smart people who I have a lot of respect for. That said, assuming I remember the discussion correctly, two were strongly in favour of explicit creation and destruction in member functions, one was mildly in favour of them, and one was mildly in favour of using C++ construction / destruction semantics, so I was in the minority.
Finally, there was no clear consensus, nor was there any specific sub-issue that the different sides of the issue strongly disagreed with. In the end the argument just petered out without anyone changing their minds.
Feel free to correct me, or comment on what follows. I am half-cut, so I make no claims for technical or journalistic accuracy here, but I want try and resolve this in my own mind. Either I am wrong, and I should change my stance, or I am right, and I need a stronger argument to present when I encounter this issue again, or both approaches have their advantages or disadvantages, and depending on the context of the design decision either could be right or wrong. In which case, I should try to identify which context is the right place to apply which approach.
So, here are the arguments, as I remember them:
General
Context: Games programming.
Explicit initialisation and destruction prevents accidental hidden construction/destruction that can be highly detrimental to performance. Implicit construction - creating an object on the stack - can look like an inexpensive operation, even when it is not. Requiring programmers to use explicit initialisation/destruction forces them to think about these issues up front, and saves time fixing performance issues later on.
Good interface design, using explicit constructors, taking care when to pass by reference or pointer and when to pass by value, avoiding casting, being careful about operator overloading is an equally effective way to avoid unwanted copies and object conversions. Requiring explicit destruction can cause bugs such as resource leaks which could be harder to track down than the overhead from implicit destruction.
My conclusion: This argument really feels like a premature optimisation to me, and the worry about resource leaks, combined with the extra work of dealing with an interface that requires objects to be explicitly initialised seems to outweigh any gains that can be had in avoiding premature pessimisation through accidental object creation/destruction inside performance critical loops. At the end of the day, a profiler can find a performance hole much quicker than a programmer can find a bug, and if your object construction/destruction is performance critical, either move it out the loop, or optimise it.
Exceptions
Context: Where the use of exceptions is inappropriate (I agree that such contexts exist).
In this context implementing constructors that fail is problematic, because of the lack of a return value. Using explicit initialisation one can implement a constructor that returns a boolean on failure, and check for it.
Constructors that can fail do so because of a failure to acquire a resource. In such cases, a class should be used that acts as a smart pointer to that resource. You can attempt to acquire the resource via a function that returns a smart pointer to it, check the result and on success pass it to the constructor of the object.
My conclusion: In my experience classes that can fail on construction are the exception, not the norm, and by requiring the acquired resource to be created by the calling code one makes the resource requirements, and thus the potential cause of failure of the class explicit. The passed in resource smart-pointer can be checked In a debug build via an assertion, providing some sort of assurance that a partially constructed object will not be used.
Memory Management
Context: Delegating memory management to the client of a library.
Okay, I honestly don't get this one - if a Initialise function can take a memory block as an argument, then why can't you pass that same memory block to the constructor. Or use placement new. Or have a custom allocator of some sort. I think I've forgotten an important detail of the pro-explicit argument here, so I think I'll call it a day for this diary, and hope to get some interesting feedback...
End
Finally, I am left wondering if we were really talking about the same thing: Were they really arguing for:
Object object;
object.Init(arg);
//...
object.Destroy();
Or were they trying to sell me a factory pattern without knowing the name?
PS: Also, pro-constructor, why pay for default initialisation, followed by creation of member variables when an initialiser list will do the job in one hit?
| < Interesting dilemma | BBC White season: 'Rivers of Blood' > |

Post to Twitter
