Returning to C++
15 March 2014A few weeks ago I pulled up a project I started during my early days in New Zealand but never got round to competing: knocking together some code that pulled H.264 video frames off a Logitech C920 web-cam. I finally got round to finishing the V4L2 bit that pulled the frames out, and for reasons of simplicity my plan was to throw these out on a UDP port for a Python script to capture and process, and I would work out Logitech's idiosyncrasies from that point onwards. However I had forgotten how laborious doing socket operations in C was. In the end I hacked together something that got the task done, but then took a side-step.
In the past I got round C being a bit verbose for network programming by writing a wrapper library for common operations, but I had lost track of where it had got to. Even if I found a copy, I doubt it would have included various tricks I discovered while working at my last company. In any case rewriting the wrappers in C++ has been on my to-do list for some time, and although I had pretty much written C++ off as a language worth learning, decided I ought to finally satisfy this itch.
Particulars of socket programming
A major issue with network programming is that it is all about socket handles and blocks of bytes, and these more often than not don't fall within neat class boundaries. Making wrappers for aselect()
based process loop feels like a padding-out not usually seen outside of government departments, so at times it is a conflict between maintaining the tight efficiency that is the culture of C programs, and actually doing a decent job of moving over to ‘proper’ C++. In hindsight a socket library was probably a poor choice.
C++ quirks
Rather than talk in-depth, I find it better to give some brief comments on things that seems to really stick out at me in the process of using C++. More often than not these are things that seem unusual rather than annoying.- C# style Accessors
- When I first came across these I found them an irritation, but pretty much ever since have regarded them as a good thing to have. In C accessing structures directly from non-structure functions did not bother me because my goal was maximum efficiency, but with C++ I would want to keep internal pointers private. Writing getter functions just felt unnatural after using both C# and Python, which allow such a function to be disguised as a variable.
- Constructors cannot return fail values
- With C-based ADTs the “creation” function would normally return a pointer to structure which allowed the return of NULL as a generic failure indication, but with C++ constructors the only way to indicate failure is to throw an exception. Problem is that most network errors such as name resolution failures are common enough that I think exceptions are inappropriate, and hence creators are largely useless for my modus-operandi.
- Non-dynamically allocated classes
- The idea is that structures (especially small ones) ought to be passed by value, but keeping these on the stack as auto variables brings some subtle differences compared to how things are done with Java and dynamically allocated class instances. Copy constructors is a topic in itself that no other language I use has, which brings some counter-intuitive quirks for those used to using the ‘new’ operator.
- Class scope domination
- I am of the school of thought that thinks that class variables should always be explicitly referenced as such, as doing so blows away a tonne of issues related to scoping. The C++ convention of writing stuff like
void Foo::bar(int value) { m_value = value; }
using Hungarian Notation prefixes to separate class and local variables grates my nerves. This is particularly irritating when writing C++ wrapper around C functions, as stuff likeSocket::listen() { listen(this->fdSocket,1); }
causes initially odd-looking errors. - Templates
- When I looked at C++ four years ago I noted how templates seemed to be influenced by Haskell's type classes, which cross-correlated with a paper I read around the same time comparing the two. Given that my Haskell is encrusted with rust I am not in a position to re-evaluate this comparison, but I am in two minds whether they add value overall to C++ or simply bloat the language. They allow content-agnostic container classes such as Vector which are very useful. But at least with gcc errors involving templates can result in error messages that are very difficult to decipher.
- Namespaces
- I had previously thought that Namespaces were somewhat redundant, as use of classes & sub-classes already got around the problem of global namespace pollution that is one of C's major pit-falls. I am still to be convinced otherwise.