Page 1 of 1
Avoiding parent-to-child and child-to-parent pointers.
Posted: Fri May 18, 2012 1:25 pm
by AlfaOmega08
I consider myself quite a good C++ programmer, and I like to "follow the rules". But I can't solve this
design problem.
It's all about my scheduler. Basically I have a Process class which contains a List<Thread *> member with pointers to it's threads.
The Process class contains PID, process path, the address space (PML4) and something more, while each thread has it's own TID, cpu context and a few other variables, AND a pointer to the parent Process.
Code: Select all
class Process
{
...
List<Thread *> threads;
...
};
class Thread
{
...
Process *parentProcess;
...
}
Everywhere I read on the web, this is highly discouraged: "Two classes needing each other would better be a single class.", and things like that. However I really need the ParentProcess pointer to read the AddressSpace field which is global to each process and not thread-specific. Having a copy of AddressSpace in each thread would be rather redundant and error-prone.
Even though my code would just work like this, I would like to remove this ugly thing from my code base. Any suggestions?
Re: Avoiding parent-to-child and child-to-parent pointers.
Posted: Fri May 18, 2012 2:15 pm
by Combuster
You'll have to show me where you got that mantra from because from my point of view it's a completely useless heuristic. It doesn't even show up on google as quoted.
What goes wrong is here that designed navigation is mixed up with designed separation of content. Pairs of information that requires exactly one of the opposite type is more efficiently stored as a whole because such a design enforces that they remain in pairs forever.
In this case there is a one-to-many relation between data, which makes the storage demand a separation of data types. That is what the class model demands.
On top of that is the navigation: if you have an instance of one class, you might or might not need to be able to find its relationships. One way of navigation is required - not storing the data means not storing any relation at all. Two ways may occasionally be necessary and it especially happens often when aggregations have some autonomous part: the parent makes the child do some work, and the child communicates back any interaction. Various languages have architected names for them: in java the implementations of the return path are called listeners. The entire collection of GUI classes is pervaded with them.
In data structures the bounds are even stronger: a graph for instance consists of a series of nodes and edges. While an edge can't exist without having a reference to two nodes, nodes can have any number of attached edges. which means that if you have any algorithm traversing the graph, you end up going from a node to an edge, and from an edge to a node, i.e. requiring both directions of navigation for any non-trivial algorithm to even work.
Short answer: what you're doing is perfectly fine.
Re: Avoiding parent-to-child and child-to-parent pointers.
Posted: Fri May 18, 2012 2:50 pm
by AlfaOmega08
Combuster wrote:You'll have to show me where you got that mantra from because from my point of view it's a completely useless heuristic. It doesn't even show up on google as quoted.
I found it on StackOverflow. I can't find the exact question, and it wasn't an exact quote, but that was the meaning
Thanks again
Re: Avoiding parent-to-child and child-to-parent pointers.
Posted: Fri May 18, 2012 7:02 pm
by bluemoon
stackoverflow is crap, I feel unlearning my programming skill just by reading the questions, and unlearn more when reading the answers.
Re: Avoiding parent-to-child and child-to-parent pointers.
Posted: Wed May 23, 2012 10:04 pm
by Ameise
I've heard of that 'rule' before. I write C++ professionally (game development)... and that rule just doesn't hold up in any industry, as far as I know.
There aren't many "rules" in regards to C++-style... everyone is unique. Some people, for instance, hate singletons, while other people use them. Use what works best for your situation. One of the beauties of C++ is that it gives you a lot of flexibility to write the code how you want, whereas other languages, like Java, don't.
Re: Avoiding parent-to-child and child-to-parent pointers.
Posted: Wed May 23, 2012 10:43 pm
by bluemoon
I only trust the rule of least surprise. When you use singleton, fine, just make it obvious and don't pretend to be a normal object
Re: Avoiding parent-to-child and child-to-parent pointers.
Posted: Thu May 24, 2012 12:28 am
by NickJohnson
All general rules are false.
Re: Avoiding parent-to-child and child-to-parent pointers.
Posted: Thu May 24, 2012 1:14 am
by Ameise
NickJohnson wrote:All general rules are false.
As a general rule, I don't dereference null pointers.
Re: Avoiding parent-to-child and child-to-parent pointers.
Posted: Thu May 24, 2012 1:55 am
by Solar
Ameise wrote:NickJohnson wrote:All general rules are false.
As a general rule, I don't dereference null pointers.
You don't?
I do.
If you have a circular dependency like that, at least think about it for a minute. I'm not sure "single class" is the general solution, though.
The very first thing I would do would be to make it a
const & instead of a non-const pointer. You don't get away with an uninitialized pointer that way, and you make it clear that Thread has no business fiddling with Process internals.
Beyond that... what Ameise said. If you find an elegant solution for avoiding the circular dependency, fine. If you don't, I wouldn't worry too much -- C++ is about efficiency, not about adhering to specific design rules. Whether there is an elegant workaround or not depends on how your classes interact with each other. And it would have to be efficient as well, since you wouldn't want to add indirections with so frequenty-used classes as these. Actually, I'm not sure I would model these as classes in the first line.
Re: Avoiding parent-to-child and child-to-parent pointers.
Posted: Thu May 24, 2012 8:38 am
by gravaera
Yo:
I'd agree with Combuster, but if you want to avoid the possibility of null pointers being dereferenced:
- If the parent process has been destroyed, it is expected that all of its child threads were destroyed along with it, so there is no chance of a stale pointer deref from the child thread's pointer to the parent.
- If the child thread is destroyed, the linked list or array would have been updated when you removed the thread, such that the list no longer points to the child thread that was removed, or the array indicated in one way or another that the index is unoccupied; still no reasonable chance of a stale or NULL pointer deref.
--My say
gravaera
Re: Avoiding parent-to-child and child-to-parent pointers.
Posted: Sun May 27, 2012 7:51 am
by OSwhatever
Doing kernel programming you end up in chicken and egg and circular dependencies situations more than general user mode programming. My kernel is full of backwards references and they are indeed needed. Kernels are full of references back and forth in order to track the resources. You can avoid them but at what cost? Having backwards reference makes you quickly determine the parent. I rather have some ugly C++ programming rather than writing politically correct C++ programming if it helps me.
Re: Avoiding parent-to-child and child-to-parent pointers.
Posted: Sun May 27, 2012 3:39 pm
by gerryg400
Solar wrote:Ameise wrote:NickJohnson wrote:All general rules are false.
As a general rule, I don't dereference null pointers.
You don't?
I do.
Nearly, but not quite
. The "->" does a dereference but the "&" cancels that out before any harm is done.