-1

(First and foremost, sorry for my English)

In order to avoid the syntactic limitation of circular dependence, I want to know if the following proposed solution is really a solution or if it has more disadventages than adventages (let's me suposse that this mutual dependence is inavoidable):

Original situation:

class B;

class A
{
   B needed;
};

class B {};

Output:

B has an incomplete type.

"Solution":

template<typename T = class B>
class tricky_A
{
    static_assert(is_same<T, B>::value, "Too tricky!!");

    T needed;
};

class B {};

using A = tricky_A<>;

int main()
{
   A a;  // At the instantiation point, B isn't an incomplete type.
}

Output:

No problems.

The common solution is to make use of pointers, but I see two problems when you really don't need them:

1) If you decide to retain pointer to other local objects, you should be sure (or the user of your class should be sure) that the life of your object is shorter than the life of the "retained" object.

2) If you decide to deal with dynamic memory, you should spend time reserving and destructing memory, and moreover it forces you to deal with exception handling, in order to make your code exception safe.

*) Longer code; smaller readability; harder mantenance; etc.

Should I use this "solution" or better to search other one?

EDIT: You are all right. This isn't a real circular dependence, so, there isn't anything to ask. This question can be closed.

EDIT2: A better question here.

Community
  • 1
  • 1
ABu
  • 10,423
  • 6
  • 52
  • 103
  • 3
    Your examples do not show any circular dependency. That makes it hard to reason about them. – R. Martinho Fernandes Apr 11 '13 at 16:21
  • To solve issue 1), you could use smart pointers – Andy Prowl Apr 11 '13 at 16:22
  • Can you show an *original situation* that has a circular dependency? What you're showing only requires `B` to be defined before `A`. – Drew Dormann Apr 11 '13 at 16:30
  • Swap definitions of A and B, such that B precedes A. Or (in the case of a real circular dependency) use (smart) pointers. Templates like yours won't help. – n. m. could be an AI Apr 11 '13 at 16:46
  • You are right, this isn't a circular dependence, and with a real circular dependency find with templates a solution is also imposible. The idea was to "delay" the instantation by means of templates, but I didn't find any solution. – ABu Apr 11 '13 at 16:48

2 Answers2

1

I think the use of pointers (and I agree with @Andy Prowl RE: smart pointers) is the preferred solution. Regarding your point about Longer code, smaller readability, harder maintenance - your "tricky" solution, while clever, violates all those tenants - it's longer, harder to read, and harder to maintain. An entry to mid-level C++ developer should know how to deal with pointers and smart pointers, however it is hard to expect them to understand the template solution you proposed.

I also do not see the circular dependency in your example; I'll assume that B also depends on A, though.

Important things to remember when dealing with this kind of design are:

  • Separating header and body is helpful
  • Prefer to do #includes in the following order: body #includes, forward-reference #includes, and finally (if necessary), header #includes
Tom
  • 2,369
  • 13
  • 21
  • "it's longer, harder to read, and harder to maintain" -- and also doesn't work in presence of circular dependencies. – n. m. could be an AI Apr 11 '13 at 16:49
  • You are right, templates make also code uglier. But smart pointer, or pointers in general, add an extra level of resources spend, and the class don't need them. – ABu Apr 11 '13 at 16:50
  • @Peregring-lk: I suppose another alternative is to try to remove the circular dependency from your design (possibly by adding a third class)? It's hard to speculate whether that's possible, without more details (and I assumed you considered that already). Also consider the other suggestions (separate header/body, etc) - you may be able to isolate the circular dependency into the definitions of A and B, in which case you wouldn't need pointers at all. – Tom Apr 11 '13 at 17:02
  • Whoops, just saw the edited question; never mind! – Tom Apr 11 '13 at 17:05
1

The premise on your design is wrong. Since there is no circular dependency in your code, there is nothing to fix (other than locating the definition of B before A) and no extra work needs to be done.

If you fix your test case to contain a real circular dependency, you will find out that your solution does not solve it. So basically you have more code that is more complex and still the same problem.

Also note that the correct way of handling a circular dependency is by breaking it. Once the circular dependency is gone, the need to manage it is also gone. There are very few good designs that contain a real circular dependency.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489