0

I'm trying to use forward declarations and d-pointers to eliminate some include dependencies. Everything is working well, except that I have used XList typedefs for readability in many places (e.g: typedef QList<X> XList).

The workaround for the typedef forward declaration issue is to use inheritance: class XList : public QList<X>{};. QList has a non-virtual destructor. Given the fact that Qt's own QStringList inherits QList<QString> and I'm not allocating XLists on the heap, do you see any problems with this workaround? Should I explicitly disallow heap allocations for the XList classes?

rpg
  • 7,746
  • 3
  • 38
  • 43
  • I wonder how important it is removing **all** include dependencies, specially compared to using unsafe, unidiomatic constructs... Sometimes you are better off standing in the middle ground: remove as many dependencies as possible without going into muddy water. – David Rodríguez - dribeas Jan 27 '10 at 19:34
  • That's what I was wondering. I'm concerned about the unidiomatic-ness of it. As far as I can determine it will be safe, especially if I statically forbid heap allocs, although I wanted to double-check on that too. – rpg Jan 28 '10 at 09:52
  • As an alternative, you could create a "FooListDeclare.h" header file, which basically does "#include \nclass Foo;\ntypedef QList FooList;". I believe this will let you declare the typdef without needing the class definition dependency in any place that you wouldn't already need it. – Caleb Huitt - cjhuitt Jan 28 '10 at 19:24

2 Answers2

1

Let's have a look at what will happen if we define XList this way:

class XList : public QList<X> {};

The following will work as expected:

  XList* x = new XList;
  delete x;

However the following won't:

  QList<X>* q = new XList;
  delete q;

QList<X>'s destructor will be called but not XList's, if any. That's what a virtual destructor in the base class will do for you.

If you never use heap allocations you should be fine, but you're preparing a trap for the maintainer following you (or even yourself in a few months).

Make sure this assumption is documented and make XList's new operator private to prevent heap instantiation as you mentioned.

The safe alternative would be making QList<X> a member of your XList, that is: prefer encapsulation to inheritance.

bltxd
  • 8,825
  • 5
  • 30
  • 44
  • I've discovered that since I am using XLists as QVariant metatypes I can't make `new` private; even though I'm not doing any allocations, QVariant does. The workaround should still work, but it is getting a little too hacky for my tastes. – rpg Jan 29 '10 at 08:55
0

QStringList doesn't define its own destructor. In this case, even if QList was used polymorphically (see blue.tuxedo's example), there isn't a problem since even though the derived class destructor won't get called, there isn't one defined.

In your case, if you require a destructor in your derived class (XList), you'll run into problems. There was a previous discussion about how to get around not being able to forward declare type definitions here:

Forward declaration of a typedef in C++

If you can avoid writing a derived class, you might be better off in the long run.

Community
  • 1
  • 1
RA.
  • 7,542
  • 1
  • 34
  • 35
  • This is a recipe for disaster... Just because in the current implementation in your system the undefined behavior does not bite you does not make the code correct. – David Rodríguez - dribeas Jan 27 '10 at 19:40
  • Agreed -- developers would have to remember not to write a destructor in the derived class. Someone will eventually forget, which would just cause hard-to-find problems. In that sense, you could argue that Qt is taking a risk with QStringList. – RA. Jan 27 '10 at 21:10
  • While QStringList doesn't define a destructor, one will be created by the compiler since the base class has a destructor. The typedef trick also won't work because I want the client header to depend neither on X nor QList. – rpg Jan 28 '10 at 09:51