0

I'm doing it in C++, I can't post the entire thing, because it's gigantic, I'll just sum it up with a simple example.I have:

class B;

class A
{
 //Members and methods...
  void DoSomething(B* owningSystem);
};

class B
{
 //Members and methods
A memberA;
}

So the problem is, A needs to know about B to use its DoSomething method and A is actually a member of B.I have an array of B's, who's number is determined at run-time.This might sound like overdoing it, but I need extreme optimization in this specific project and I was wondering - is it better to pass B* owningSystem or to just store a pointer of each B inside its A member?I don't think DoSomething will ever be inlined, since their count and pointer locations are determined at run-time, but I can chose storing a pointer vs. passing it in the function.I need to minimize the overhead at this point by as much as I can, it's critical.I'm open to any suggestions, please

1
  • Hello! A couple things. When I find myself coding A depends on B and B depends on A, I usually find that I have designed something poorly and should rethink my design. Second, I highly suspect that a pointer being included or not in the method declaration will impact the code's performance nearly as much as many other factors - can you give us more detail on the rest of the code?
    – J Trana
    Jan 11, 2014 at 6:38

2 Answers 2

2

What I found from all kinds of trial an error is that when you have components with circular dependency on each other (more so in C++ than in dynamic languages like python), you are asking for trouble, so I always make it a point of always defining a strict hierarchical relationship between classes.

In this case it seems that B is a higher level class than A, so let's keep it that way. How about something like this:

typedef interface struct;             // in MSVC this is built into compiler

interface IOwnerOfA {
    virtual int someFunctionCall() = 0;
}

class A {
    IOwnerOfA*  m_pOwner;

    void DoSomething() { .... bunch of code; m_pOwner->someFunctionCall(); .... }
}

class B : private IOwnerOfA {
    // yeah, cast is optional but I like them in these cases
    B() : m_a( static_cast< IOwnerOfA* >( this ) {}   

    virtual int someFunctionCall() { 
        ... provide specific functionality A needs;
        and nothing else;
    }

    A        m_a;
}

So now the hierarchy is IOwnerOfA <-- A <--- B. Everyone knows about the interface, B knows of A, A knows nothing about B, so tomorrow you could have C using A without having to make any changes in A.

As far as your question about storing a member variable vs. pass in as parameter into DoSomething(), that's really up to you. If it is only one isolated place, I'd probably pass into a parameter. If the relationship between classes really is that B is an "owner" of A and in A needs to call back into B (via IOwnerOfA interface) in a number of places, then store as a member.

Another alternative for you to consider (if you are doing a one off in one place) is instead of using interfaces and class pointers, you can take a functional approach and have DoSomething() accept std::function as a parameter type. Then use std::bind() to pass in a bound member function. Might sound a bit crazy, but it's actually somewhat straightforward (except for the compiler errors if you get something wrong) and very flexible (once you get past the compiler errors)

To add to what @JTrana, commented on. There are definitely cases where B owns A and for whatever reason A needs to callback into B. If you need to do this, the only two options I see are using interface (yes one extra level of indirection) and using direct types (circular dependency). Between those 2 choices, extra complexity of the interface is a winner for me. However, these true cases are few and far between. Most of the time you might be able to refactor your app so you don't need to do this circular loop.

Consider if part of B that A needs could be switched out into a smaller C class:

class C {   // contains some commonly used functionality
}

class A {
    DoSomething( C* pCommonGuy) { .... }
}

class B {
    A  m_a;
    C  m_c;
}
3
  • I think this is a good answer - I definitely agree with the bit about the A referring to B and vice versa being a bit troublesome. I also liked the bit about switching to a functional approach at the end, I think that may help you get the best performance for this part of your code. The only thing I'd also throw out there is that the use of an interface such as IOwnerOfA might use an extra level of indirection - but I wonder if this isn't optimized away in compilation..?
    – J Trana
    Jan 11, 2014 at 6:45
  • @JTrana: how about that ^^ :) And no, generally interface calls, due to the nature of virtual function calls with their fancy vtables would not get optimized away.
    – DXM
    Jan 11, 2014 at 6:53
  • Cool. Hopefully this helps out the OP. I'm kind of curious to see what the application is that he thinks this might be a performance issue..? I suspect that if we had more context we could help see how this fits into the bigger picture performance-wise.
    – J Trana
    Jan 11, 2014 at 7:00
0

If the B* is a member of A, then I think you'll have two dereferences every time you use it since m_b->Action(); is really this->m_b->Action();. If you pass the pointer as an argument, there's only one dereference.

It's possible that passing the argument might slightly slow the function call to A::DoSomething() but passing a single pointer must have nearly zero overhead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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