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.

I have project written in C++ that I am working on which has a parent-child relationship where each child has only one parent. I had previously decided after looking at this post that I would make the children know nothing of their parents.

A little background on my project before I go into my question: The parents in this situation are objects representing a collection of interlinked computational "blocks". The parent (The "Model" class) takes in one or more input values, runs them through its blocks, and the blocks return back one or more output values. The child objects are the Blocks and a Block is owned by exactly one Model. The issue is that a certain kind of Block can contain a Model so that I can nest them and re-use models. Although most blocks know nothing of the Model class, the ModelBlock (inheriting Block) knows about Models and is allowed to encapsulate a Model.

The Question: The above seemed to be working pretty well, at least in the console version of my application. However, I need a GUI to be able to create any large Model without losing my mind and so I have started making one. The issue has reared its ugly head again when I realized that the Blocks in general need to know about their Model so that ModelBlocks can inform a Model when it is being used inside of another Model. This is so that I can easily find "orphaned" Models that are not the root model and not used in any other context (meaning they will never be run). I guess I could make it specific to ModelBlocks, but if I'm going to do something like that, why not make it apply to all the blocks?

In C#, its seemingly not a bad practice to use a circular reference to accomplish this (Entity Framework does it up the wazoo...it wreaks havoc with serializers). However, it seems very taboo in C++ to use circular references. So, I am wondering if the above is a legitimate use. Were I to do this, Blocks would be informed of their parent Model's destruction so that they know if they are orphans. Even if the above isn't, are the legitimate uses for circular references in C++ since they seem to be relatively common other languages (of course, that's assuming that those programs in those other languages using circular references don't have serious design issues)?

If I didn't explain my question well enough just let me know and I'll try to clarify.

EDIT: I should mention that the actual implementations are separate from all this since I am using interfaces (classes with all pure virtual functions) to define how a block looks or how a model looks.

Here is a partial class diagram with my proposed changes: http://oi50.tinypic.com/16c8cwn.jpg

Here is the source: https://github.com/kcuzner/Simulate/tree/develop. If you feel like building it, it depends on Qt >= 4.7, boost >= 1.52. The projects are Qt-Creator projects. Console and GUI depend on Engine.

share|improve this question

4 Answers 4

up vote 15 down vote accepted

There's nothing wrong with using a non-owning pointer to someone who points back to you. Just make sure it's not owning.

share|improve this answer
2  
+1 Well summed up! I was about to write a paragraph but this is spot on. I think it needs a bit of clarification as to how not owning (like not using shared_ptr or unique_ptr for this - the meaning of "owning" which surprisingly few people understand), maybe after an horizontal bar?. –  Klaim Feb 18 '13 at 9:10
    
Since my blocks know if their parent is destroyed, but have no control over that, would you consider that non-owning? They basically have the logic behind a weak_ptr implemented towards their parent. –  Los Frijoles Feb 18 '13 at 19:48
1  
Ownership's core principle is having (at least some sort of) a say of when another object is destroyed. If they don't control that, then they definitely don't own it. –  DeadMG Feb 18 '13 at 23:06

You might want to use shared_ptr for owning links and weak_ptr for non owning links (child to parent). That way you can destroy the parent, and the child can check if parent exists.

share|improve this answer
1  
Actually shared_ptr is kind of frowned upon in C++. Unique ownership is preferred where possible. –  Jan Hudec Feb 18 '13 at 9:13
2  
The non-owning links in case like this should be plain dumb pointers. They point to owner, so the design guarantees they'll never go stale and the overhead of weak_ptr, which is pretty big, is not needed. –  Jan Hudec Feb 18 '13 at 9:14
    
@JanHudec I was going by this sentence "Were I to do this, Blocks would be informed of their parent Model's destruction so that they know if they are orphans.", perhaps I have misunderstood –  Karthik T Feb 18 '13 at 9:16
    
Hm, you are right, that complicates matters more than a bit. –  Jan Hudec Feb 18 '13 at 9:28
1  
@Jan Hudec: I imagine that shared pointers are slower than unique pointers and therefore unique pointers should be used when possible. On the other hand, the shared case seems to occur much more often than the unique case. At least in my experience. –  Giorgio Feb 18 '13 at 10:03

You can use void * (or IUnknown *) to achieve loose coupling and reduce code complexity. It eliminates circular referencing in C++ header files.

// Model.h
class CModel
{
public:
    void addBlock(char *str, void** ppBlock);
};

// Block.h
class CBlock
{
public:
    void getParent(void** ppModel);
};

Then with appropriate casting, you can get what you need, for example:

#include "Model.h"
#include "Block.h"

// ...

CModel model;
CBlock *pBlock = NULL;
model.addBlock("something", (void**) &pBlock);

CModel *pParent = NULL;
pBlock->getParent((void**) &pParent);

If you add a reference counting system and smart pointers, then, you will have an ecosystem similar to ATL/COM.

share|improve this answer

You know there are problems where the only good answer is to use a system with better garbage collection than any portable C++ library supplies.

I could name some, but they're pretty involved. Examples involve things like prolog embedded in C++ and expression trees used in a compiler.

I've got a portable mark and sweep garbage collection library working and 90% finished at the moment. Since C++ has limitations it's not as unrestricted as C#'s - the basic restriction being that objects belong to a thread, each thread has its own garbage collector, and references ACROSS threads have to fall back on atomically handled reference counts like shared_ptr and boost's intrusive_ptr so cycles that involve ownership by more than one thread won't be collected. Also in the current version, weak pointers are only available in the owning thread.

After lots of thought, these limits seem like the best compromise you can get with a portable C++ library.

share|improve this answer
1  
It's not clear to me how this answers the question that was asked (even if it is something cool that you've done). You might want to clarify that. –  Donal Fellows May 11 at 7:35

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.