Qt4 (Console) to Boost migration
(Note: this contains flame and half knowledge)
The last two months, I hat to migrate one small project from Qt4 to Boost to make it fit better into one bigger project. Fortunately it did not contain GUI stuff (this may be remain Qt).
This migration showed me three things:
1. Qt does improve a lot of things and you get accustomed to it.
2. Qt signals suck.
3. What to replace with what.
Cool Objects
Once you get to know QVector, QByteArray or QString you do not really like the old plain C++ equivalents anymore. Want to replace some Strings in another String? QString::replaceAll does it. Like natural command naming? QVector::append sounds better than std::vector::push_back. Don't like iterators: Use QByteArray::append (/* some String*/) instead of std::vector::append (string.begin(), string.end()).
Also XML stuff and Networking is a dream. Always wanted to open a TCP Socket? Class TCPSocket is your friend. No templates; no weird Mixin Patterns for getting things done computers do for > 20 years now.
Signal this!
Qt signals are very cool, indeed. You can combine them during Runtime, the overhead is not big, and also the moc-preprocessor is not your problem if you have a good build tool like cmake. But don't be forced to write them by Hand.
- They will checked on Runtime. You will receive error messages (without the current position) if the signal doesn't exist. The compiler errors of template based signal mechanisms are also nearly impossible to read, but at least they come earlier. The only good system I saw so far (in an C-Like-Environment), is the one in ObjC used by Apples' Xcode. Xcode gives you warnings on compile time that the signal may not exist - while it still get bound during compile time (like in Qt).
- They don't have real scope handling for Enums. So if your enum is inside bla::MyClass::MyEnum, you cannot call the signal at first class::MyEnum and then bla::MyClass::MyEnum. It will not be found
- It is not less much to write, compare:
// Qt way
QObject::connect (obj1, SIGNAL (changedState (bla::State)), this, SLOT (onChangedState (bla::State)))
// Boost way
obj1->changedState()->connect (boost::bind (MyClass::onChangedState, this, _1));
So, what to replace?
I just used parts of Qt in the project, but here is a list how to replace things so far. Maybe it will get longer if I have more time.
- Qt Signals: I used boost::signals2 (found in newer boost versions). It is the thread safe version of boost::signals and doesn't need the library. But the compile times are slightly longer.
- Qt XML library: I found RapidXML to be of easy use. Of course the feature set is very small and it seems to parse only parts of XML right (so no validation or real namespace handling). On the other hand it is really fast
- Qt data types. Of course you have to take the standard types. But you can pimp them with boost::smart_ptr. QByteArray can be replaced by an improved vairant of std::vector<char> (on most machines). You can even access the memory regions by &(*vec.begin()) (thats not standard, but works in Windows and GCC). The QString is more complicaed, boost encapsulates some nice string functions, but they usage just looks horrible. On the other hand C++ output operator streaming is much easyier to implement and understood by all STL streams.
- Logging. QDebug () there are lot of C++ Logging Libraries but few simple ones. I wrote one myself (less than 200 LOC and syntax compatible to my clients one, so that they can replace it). But on bigger projects there are things like a C++ variant of Log4j.
- QNetworking We decided to use boost::asio for this. But this library heavily differs from QTcpSocket or QSslSocket. On the other hand you gain a bit by having no thread constraints (the Qt classes have them, QTcpSocket has to be used from the Thread how created it). With a small intermediate Layer you maybe get the same usage like in Qt.
- If you want small binaries, ensure that your GCC is very new. I found differences of 50% between GCC 4.2 and GCC 4.4 (on 64Bit). Boosts autogenerated code is ideal to compress (saving 80% with LZMA is no problem, even after stripping and size optimized compilation)