On Fri, 15 Sep 2006 11:16:21 -0300, Robert Kindred
I can think of one example for not fully constructing objects:
I've got some multi-threaded programs where I have found that it is quite convenient for each of my threads to be a C++ object. The private thread variables are C++ private data members. These threads cooperate with one another by sending messages to each other through locking message queues. In this way private data members do not need to be locked, as each message is processed sequentially.
The problem is in starting up. If each one of these threads knows about each other via some method (pointer, or reference), then when a thread starts up its own business, whatever that is, then most likely it will start generating data and sending messages. When it tries to send a message to a thread that does not yet exist, BOOM!!! (yes, I have experienced this boom).
My solution to this is not to start the threads running in the constructor. I can create all of the thread objects in any order I like, then I can start them running as threads in any order that I like, through a member function call to each one. If a thread sends a message to another thread object not yet running, then the message simply waits in his queue, until he wakes up and begins processing messages.
Consequently, at program shutdown time, one cannot just start deleting thread objects. If you were to delete a thread object that other thread objects are messaging, BOOM!! (or as they say in this newsgroup, undefined behavior). My answer to this is to signal each thread to come to a stop on its own accord. Once all threads are stopped, then they can be deleted in any order. So, I don't have monolithic destructors, either.
Of course, you may consider a thread object that is not yet running is actually fully constructed. I am not sure of the definition.
I find this situation sometimes too. My solution follows Stroustrup's advice. When I can't break a cycle I create an entity that stands for the collection of interrelated instances/classes. In your example each thread object maintains an invariant, but the collection of threads have a stronger invariant than the sum of invariants. That can be seen in that both construction and destruction require special care. In Haskell some cases of two phase construction can be avoided because of it's lazy nature. You can have references to objects that still don't exist, without having destructive assignments. It really rocks: http://www.haskell.org/hawiki/TyingTheKnot Bruno