Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

So if I understand correctly, from SOLID design principles, every class should keep a single responsibility.

So there should be one class that creates and manages a resources, a second class that does resource processing/update, the third class that connects the resource to some other resource and so on.

The question is, how do you cleanly express that in code?

Because, in C++, the class destruction order plays an important role.

So you basically come to a situation where you get

ResourceClassInstanceManager cf;//does the ResourceClass creation, accounting and destruction?
ResourceClass &rcInstance = cf.GetResourceClass();//creates the instance of resource
ResourceClassUpdater rcu(&rcInstance);//updater that works on the class instance
ResourceConnector rcc(&rcInstance, &instanceOfAnotherClass);

The problem here is that if cf leaves the scope first, or rcInstance is deleted before rcu or rcc. The other classes will still reference the nonexisting instance of ResourceClass.

This seems somewhat messy, as the whole creation/destruction chain has to be followed very carefully, and becomes really troubling as soon as you have pointers to objects and deeper nesting levels.

Is there a clean solution for this design problem?

share|improve this question
    
You could always use reference counting (shared_ptr) and not worry about the issue at all. –  Charles Salvia Aug 19 '11 at 13:58
    
Smart pointers are a good solution, shame that they add a layer of extra complexity, though (I'm not afraid of pointers, but they do add some gotchas). But yes, reference passing in this instance is actually "throwing bad refs around", and by switching object construction and therefore destructor sequence, the AV can creep up unexpectedly. Thank you for the criticism. –  Coder Aug 25 '11 at 22:59
add comment

3 Answers

up vote 1 down vote accepted

One solution could be to use smart pointers (for example, in Qt you have the class QPointer) instead of references: as soon as an object is destroyed, a smart pointer that was pointing to it will be set to NULL. So you will never be trying to reference an object that has been already destroyed.

Of course, you also need a mechanism to avoid a NULL pointer exception, e.g. you should check the value of a smart pointer before dereferencing it.

Additional Information

In my opinion, an important principle is that it must be clear which parts of the code (e.g. which objects) manage a certain object, and which parts of the code only use (or observe) the object.

My usual strategy is the following.

All managers wrap the pointer to a given object in a boost::shared_pointer (see also DeadMG's suggestion). This is a smart pointer with reference counting: when the last smart pointer for an object is destroyed, the referenced (managed) object is also destroyed.

In addition, I have observers, which just store a pointer to the object but have no influence on its lifetime. I used QPointer for this: when the object gets destroyed, the QPointer is automatically set to NULL. In this way, the observer can detect that the object does not exist any longer.

An important point here, is that objects themselves may observe or manage other objects. Pointers between objects lead to object graphs, but normally you can decompose this graph into an object tree (aggregation) with cross references (ordinary associations) between siblings of the tree.

In this case, I use shared pointers to implement the father/child relationship (each node manages its children, and the children are automatically destroyed when the father is destroyed), and QPointer's for references between children or for the child/parent relationship.

share|improve this answer
add comment

No. Destruction happens in reverse order of construction. rcc will be destroyed first. The fundamental problem here is that you're throwing around bad references- that is, you're throwing out a reference to a ResourceClass with no control over it. It should be wrapped in an appropriate smart pointer.

Also, I find your class design very highly questionable. What actually is the job of any of those classes except the ResourceClass itself? I don't need a helper class to call new, or call an update or connect function on a ResourceClass.

share|improve this answer
add comment

I think that you are using a definition of "responsibility" that is too narrow. Your defintion of "reponsibility" seems to be more like "activity" or "action".

I would expect a resource class' responsibility to be able to be stated in a sentence something like: "Manage the lifetime and access to X, allowing updates and connections to X."

A class is a larger entity than, say, a function so you should expect its responsibility to be broader. A member function would normally have a narrower responsibility but it can also have a single responsibility. For example the Update member function might have the responsiblity of "validiating and executing the requested update to X".

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.