Eric Day

Thoughts, code, and other oddments.
Dark | Light

< || >

C++, or Something Like It

March 5th, 2010

I’ve developed primarily in C most of my career, and recently decided to give C++ a shot as my “primary language” due to hacking on Drizzle and MySQL. The past few months I’ve read and experimented with most features C++ provides over C, including reading Scott Meyer’s excellent “Effective” series books (highly recommended). Along the way I’ve been developing a project I’ve wanted to write for a while, and I’m finding some features to be problematic. I thought I’d share these issues so others can be aware of them and perhaps I can learn better workarounds.

The project I’ve been working on uses dynamic shared object loading at runtime (using dlopen() and friends), is threaded, and has about every strict compiler warning on you can find and being treated as errors (thanks to Monty Taylor’s pandora-build project). I’m also testing on various architectures and compilers, including Linux, OpenSolaris, and OSX. I also have been trying my best to avoid any dependencies on large C++ libraries like Boost and just stick to the standard language and STL. With these requirements in mind, here are the issues I’ve run into:

Can’t Reliably Use Exceptions

My first pass relied on exceptions, but this proved problematic on some architectures as soon as custom exceptions were being throw across module boundaries. This comes down to ABI issues for some shared object formats generated by some compiler versions. While you can make it work in some environments, it’s not going to be portable. This means I’ve had to catch exceptions closer to where they are throw, requiring a lot more try/catch blocks, and not being able to take full advantage of automatic stack cleanup. This also means resorting back to the C way or handling exceptions: returning and checking return codes while generating error strings. To be completely exception safe, this means not using std::string for error returns since they can throw exceptions while building useful error messages. Not using exceptions has had a viral effect throughout the rest of the design of the code, making it look more like C. I was a bit disappointed by this, as not having to check every function’s return code was keeping the code very clean. :)

Limited Use of the STL and std::string

I was excited to take advantage of the STL, as writing things like doubly-linked lists and hash tables for every C struct was getting a bit old (I did have a set of macros I used, but they were not the most popular in some circles because of certain C-preprocessor features). When I learned more about the internals of the STL, and how it relies heavily on copying objects, my heart sunk a little. It completely makes sense in the design, it’s just not as efficient as it could be (especially coming from a place where I would optimize to reduce pointer copies in C). No worries, I just created private copy constructors/assignment operators and only used pointers to objects. This came with it’s own set of issues with pointer management and avoiding leaks if the ‘new’ operator were to fail. Once working out the memory management issues, there were still exceptions to watch out for, including figuring out all the methods that may throw (due to an internal allocation usually). This is especially annoying when doing simple std::string operations like assignment or concatenation, and having to always catch around those. With other annoyances like the reference-to-reference issues and std::unary_function having a non-virtual destuctor, I’ve ended up using a watered down set of STL algorithms and resorted to a mix of non-STL containers and custom algorithms for some things. The lack of thread safety concerns in STL containers and differences in implementations have also lead me to not use STL containers for thread communication (using a mutex for every access is not efficient).

Conclusion

For the sake of consistency, I’ve wondered if it’s worth incorporating STL components? Is it better to have a mix or none at all? This would leave only inheritance, polymorphism, member protections, namespaces, and automatic object destruction the only C++ features being used. These are still very good reasons to use C++, but I’ve found the transition to not be as productive as I had hoped. I am very curious to hear other folks thoughts on their experience with any of the issues above.

Posted in Drizzle, Main, MySQL

4 Responses to "C++, or Something Like It"

  1. Shlomi Noach says:

    Checking up on stack trace is not an easy task on C++, and depends on your compiler. With careful planning, you should be able to get along well with Exceptions based C++ application.
    In particular, check these global-purpose exception clauses:
    catch(…)
    {
    }
    set_unexpected(pointer_to_int_global_function_which_handles_uncaught_exceptions)

    These should help out with finding out about undocumented or unknown exceptions. If you already know these, there’s not too much I can add.

    STL is widely used. It could be better! But it’s well debugged and documented. Some things just aren’t well thought of, IMHO (e.g. conversion between std:string and char *).
    I haven’t has too much experience with STL myself, but I would use it on a new design.

    PS, I recommend “Thinkin in C++” by Bruce Eckel, which is just an excellent book, especially targeted at C programmers.

  2. Aivars says:

    We solved dlopen() and exception problem by switching to GCC 4.2+ and figuring out how to use linker on each platform (Solaris, HP-UX, AIX and Linux). Before that we did not use dlopen() + exceptions and forced static linking on AIX, because older GCC versions had problems with throwing exceptions even over shared library boundaries.

    As for efficiency of STL implementation – for most of the time we just don’t care. Profiling usually shows that application spends most of its time in Oracle or writing logfiles or just doing something stupid and redundant. But that’s probably specific to our application and developers.

  3. Monty Taylor says:

    Aivars – could you expand on the use of the linker you mentioned? I’m maintaining the build system that Eric is using and if there is a way I can improve it here to support him, I’d love to do that.

  4. Andrey says:

    Boost can help you a lot. The shared_ptr/shared_array and scoped_ptr/scoped_array (http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/smart_ptr.htm) and friends really simplify the management of objects, especially in code that can throw everywhere, which means leaks are waiting everywhere. The beauty of Boost is that it consists mostly of headers, which means that if you don’t touch some Boost libraries you don’t need to ship any boost compiled code.
    About the ABI issue. Try returning std::string (object reference, not a pointer) from your library and another code to use it. You will realize that only C is portable because if your library is compiled with VS and debug then std::string is pretty different as an object than in the client code that uses VS and builds for release. You expect std::string to be std::string but it is not.
    Another problem are different CRT versions on windows. Library compiled and shipped will use one CRT and when deployed the client code might use another CRT. If you are not careful in the API design then the client will try to free memory allocated with another allocator and crash!

Leave a Reply


< || >
Blog
Wiki
About
Resume
RSS
Comments

E-Mail
Launchpad
LinkedIn
Twitter
identi.ca
Facebook

OpenStack
Scale Stack
Gearman
NW Veg
Veg Food & Fit

Linux On Laptops