Boost logo

Boost :

From: Gennadiy Rozental (gennadiy.rozental_at_[hidden])
Date: 2005-07-29 00:01:23


> A) class destructors preferably shouldn't be doing anything smart
>
> I don't understand the reasoning behind this... class destructors exist
> so that resources can be disposed of intelligently. If this were valid
> then we wouldn't have reference counted smart pointers.

Disposing of resource this instance own is one (simple) thing. Meddle with
other templates is something completely different (complex) and in most
cases would involve function invocations which in turn may throw an
exceptions and all the hell break loose. On the other hand if destructors
are simple they are independent and all this complex machinery in
unnecessary.

> B) if teardown procedure is not trivial it's part of normal program flow
> and should reside within main() bounds
>
> This forces the highest level code to be aware of every detail that
> needs to be cleaned up. What if a library wants to use some sort of
> resource manager in the background? Should it force client code to be
> aware that said resource manager exists, and make client code
> responsible for cleaning it up?

Client code should be aware about single function teardown() that user
should call somewhere during program exit. After that any attempts to access
library functionality is invalid. If you want you could even automate it by
RADII based manager that does lib_init() in constructor and lib_teardown()
in destructor.

> This seems like a C-oriented way of thinking, and does not scale.

Both statements seems to be born out of thin air. Could you elaborate?

> C) it doesn't seem to be ever portable to rely on order of global
> variables destruction in different libraries (dynamic or static)
>
> The portable means to control this is with mini Meyers singletons. It
> is guaranteed by the standard that local static variables will be
> destroyed in reverse order of the completion of their constructors.
> Thus with the following code:
>
> Foo & A ( )
> {
> static Foo foo;
> return foo;
> }
>
> Bar & B ( )
> {
> A ( );
> static Bar bar;
> return bar;
> }
>
> If B is called, then B's bar will definitely be destroyed after A's foo.

That was my point that Meyers singletons is all that we need. Anything
smarter than that (IOW all these games with enforcing unnatural order of
destruction) is just unnecessary "smart".

> D) it's unreasonable to expect all global variables to employ single
> manager facility within bound any reasonably big application
>
> Hence the policy based design. Related singletons can use related
> lifetime managers, and unrelated singletons need not be concerned about
> each other. The dependency_lifetime solution handles this concern
> especially well, as using reference counted smart pointers to singleton
> instances does not require a master manager at all.

This still assumes that all world will be using your framework to implement
singletons. Let say you need to use third party singleton in your destructor
that is implemented by some arrogant somebody without regards to your order
management?

> E) if any teardown procedure fails it's really non-trivial to insure
> proper destruction for the rest of globals (if possible at all), while
> reporting an error may be impossible/difficult.
>
> This is not a problem with singletons, but a more general problem which
> client code must be concerned about. Singletons which have a well
> defined order of destruction can help client code to organize a well
> structured solution.

Singletons with nontrivial logic in destructors ... should not do this in
destructor. And this is not a general problem. It's problem with all global
variables that destructed in afterlife (most main() exit)

> Many of your other points do not still apply, as there does exist a
> scalable mechanism to control destruction order, and the new design does
> take multi-threading into consideration.

Even if it exist (which you did not prove AFAICT) don't go there. "Don't go
in language dark corners" experts told recently.

> Just because it is relatively
> inefficient to access a singleton shared between threads safely does not
> mean that it is a bad approach.

Just because it is relatively inefficient it makes it completely unusable.
MT in many cases are very performance aware and singleton is a performance
bottleneck.

> Any method employed to communicate
> between threads will be somewhat expensive. The goal is to minimize the
> amount of communication required, not to throw out communication
> mechanisms all together.

Not every method. Just init you singleton in main thread and destroy in main
thread. And no need to care about synchronization at all.

> With regard to your desire for a different interface, it is easy enough
> to create an instance method which wraps the smart pointer and just
> returns a raw reference. However, choosing to do so does eliminate all
> thread safety,

 No need to synch on instance access at all.

> destroys the possibility of delaying creation until a
> member function is accessed,
I do not see how. Third recommended technique in original post cover this.

> and ensures that your references will not
> stay up to date if the singleton instance is destroyed.

Don't keep references and/or don't destroy your global variables in a middle
of program execution.

> It feels like much of your argument is against object oriented
> principles in general, and advocates a single flow of execution.

Let's not make unfounded accusations. Where did you see me argue against
OOD?

> While this may be reliable for smaller programs, I have no idea how you
> can
> expect that solution to scale.

And I have know idea what you mean. It would be good to base your statements
with at least examples.

Regards,

Gennadiy


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk