Posts Tagged ‘c++’

Inheritance misunderstood

Thursday, May 27th, 2010

In C++ inheritance is not for code reuse. Full stop. Think subtyping. Think interface. Think substitution. Think specification. Learn about LSP – Liskov Substitution Principle. Never ever think reuse.

I’m amazed, shamefully, how often I forget about it and I drift away thinking how to save on keyboard use and typing.

Preparing Quickbook for Boost.Geometry

Sunday, February 7th, 2010

Generic Geometry Library (GGL)I’ve just started writing Boost.Geometry (aka GGL) documentation in Quickbook. It is a lightweight format and parser being developed by Boost used to prepare technical documentation for software, mainly for for Boost C++ Libraries. Quickbook files (.qbk) are used as input for BoostDoc which in turn is an extension of DocBook.

Quickbook is a textual format, it feels quite similar to AsciiDoc or some sort of Wiki dialect but dedicated for documenting C++ programming. It is extremely easy to grasp while drinking a single short coffee.

Anyway, it seems it is going to be a quite a book after all elements of Boost.Geometry are documented. One of the challenge I’ve found is to collect all bits necessary to document C++ concepts defined by Boost.Geometry. Unfortunately, Doxygen is not an ideal tool for this purpose, so current version of the documentation lacks of some sections of concepts description. So, I have to dig the source code to find out formal definitions and details of valid expressions and semantics.

Another challenge related to concepts is to find best way to structure their documentation. I started to browse documentation of existing Boost libraries looking for examples and what I found is that there is no best example. Various libraries document concepts in very different way.

A concept is a set of requirements consisting of valid expressions, associated types, invariants, and complexity guarantees

David Abrahams, Generic Programming Techniques

For example, neatly Boost.Fusion documents concepts with Quickbook, though some elements seem to be omitted. Boost.Graph doesn’t document with Quickbook, looks good, but some details are missing to me, for instance, titles in headers of tables saying what is what is return type and pre-/post-condition for valid expressions, etc. Documentation of Boost.IOStreams concepts sound well. On the other hand, Boost.GIL is an example of why Doxygen should not be used to document concepts of a C++ library.

It looks to me the old good Standard Template Library Programmer’s Guide at SGI is still a best and most complete example of how C++ concepts should be documented.

Given these experiences, I started to think of a way to improve the way concepts are documented within Boost. I believe it would be a good idea to have predefined block for concept in Quickbook. Something along these lines:

[concepttype [Point Concept]
  [this is a concept for 0-dimensional geometry]
  [notation
    [term 1] [description 1]
  ]
  [refinement [concept 1] [concept 2]]
  [associated
    [type 1] [description 1]
  ]
  [expressions
    [name 1 [expr 1]
      [type requirement 1] [return type 1]
  ]
  [semantics
    [name 1 [expr 1]
      [precondition 1] [semantic 1] [postcondition 1]
  ]
  [complexity [...]]
  [invariants
    [invariant 1] [description 1]
  ]
  [models [model 1] [model 2]]
  [notes
    [ note 1] [ note 1]
  ]
  [seealso ...]
]

I posted my proposal to boost-docs list explaining the motivation in details. It’s an interesting experience of a C++ documentation craftsman, anyway. (BTW, Daniel James just announced Quickbook port to Spirit 2.)

illegal token on right side of ‘::’

Wednesday, January 27th, 2010

libLAS - ASPRS LiDAR data translation toolsetOne of libLAS users reported that when use of #include <liblas/lasreader.hpp> in his application compiled with Visual C++ 10.0 from Visual Studio 2010 cause this error:

utility.hpp(253): error C2589: '(' : illegal token on right side of '::'

The error is an incarnation of a very well-known problem in Visual C++ when using the C++ Standard Library elements, especially the Standard Template Library, in Windows API-based programs. As libLAS library does use the C++ library, so does a user’s application if includes libLAS headers.

The problem is caused by conflicting definitions of min() and max() macros defined in windef.h header. Macros in C++ are scope-less evil, especially if defined in public headers using such extremely unique names as min or max. The fact that Microsoft defined it way before C++ was born absolves them at large, but for the Spirit sake, they should learn the lesson and disable it for good in C++ mode (but not yet another MS-specific way!). No one who’s sane need or want to use them!

Pie in the sky. In the meantime, C++ programmers as the libLAS user who reported this problem have to deal with it on their own. The easiest way is to check CodeProject or Q143208 or search (not google) for solution like #define NOMINMAX for Visual C++ compiler.

However, is another option is to apply a simple trick to call of *::min() or *::max() functions (i.e. std::min() or std::max() which effectively prevents macro substitution, so the Visual C++ compiler (or any other compiler with similar problem) does not complain about illegal token. The trick is to wrap function name, fully qualified name, with parentheses:

(std::min)(x, y);

In most cases of use of C++ Standard Library as described above, it is required for the following functions:

(std::min)(x, y);
(std::max)(x, y);
(std::numeric_limits<T>::min)();
(std::numeric_limits<T>::max)();

In case a user-defined type has a member function with exactly the same name as a macro present in global scope (macros always live in global scope!), it may be necessary to apply the very same trick when a member function is called on an object:

template <typename T, int Size>
struct Series
{
  T min() { return *(std::min_element(s, s + Size); }
  T& operator[](int index) { return s[index]; }
private:
  T s[Size];
};

Series<int, 3> s;
s[0] = 2;
s[1] = 3;
s[2] = 1;

int m = (s.min)(); // long way, but here is the trick

There is one side effect which may be an inconvenience. This trick disables argument dependent name lookup (ADL, aka Koenig lookup).

Exceptions to error codes translation made simple

Friday, January 15th, 2010

On many occasions, it is not possible or it’s even forbidden to let an exception thrown to sneak out of a function. On many occasions, it is necessary to sink all exceptions in place where they may occur and translate exceptions thrown to error codes. I have observed it’s not uncommon software projects stick to some rules about how they handle exceptions, like:

  • I’m sorry, I don’t like the fat & slow hippo RTTI (BTW, hippo can run 50 km/h!).
  • My function, class, library never ever throws exceptions.
  • I use exceptions to signal error conditions only from and within internal components, but never let them to cross the line drawn by public interfaces.
  • I write C wrapper for C++ library, I have to translate exceptions to error codes.
  • Exceptions? I have no idea who was mad enough to invent such a $%&@ beast. Forget!

Shortly, not for everyone exceptions are kosher, gluten and lactose-free meals.

Even if exceptions are not kosher, it is necessary to love & deal with them because…use of standard library elements or 3rd-party components which may throw, coding conventions ignorance within a team, just-in-case prevention, etc. Handling exceptions may make code very messy (check how Java camp deals database connection problems). It is possible to handle exceptions and maintain clean code.

Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

Martin Fowler

Below is a simple example showing how to solve some of the problems pointed above. The basic idea is to implement one-for-all exceptions handler where all types of exceptions possible to be thrown are killed and translated to specified error code, exceptions have chance to send S.O.S. code before sinking.

#include <cassert>
#include <exception>
#include <iostream>
#include <stdexcept>

template <typename T>
inline T const& handle_exception(char const* const who, T const& rc)
{
    try
    {
        throw;
    }
    catch (int e)
    {
        std::cerr << who << " caught int: " << e << std::endl;
    }
    catch (char const* e)
    {
        std::cerr << who << " caught c-string: " << e << std::endl;
    }
    catch (std::exception const& e)
    {
        std::cerr << who << " caught std::exception: " << e.what() << std::endl;
    }
    return rc;
}

#define EXCEPTION_TRY() \
    try {

#define EXCEPTION_CATCH_AND_RETURN(success, failure) \
    } catch (...) { \
        return handle_exception(__FUNCTION__, failure); \
    } \
    return success;

// use it to exit void function on error
#define EXCEPTION_CATCH_AND_EXIT() \
    } catch (...) { handle_exception(__FUNCTION__, false); \
    return; }

template <typename T>
class number
{
public:
    // public ctor, may throw
    number(T value) : value_(value)
    {
        if (value != value)
            throw "value is NaN";
    }

    // public save division, never throws
    bool divide_s(double& result, T const& den) const
    {
        EXCEPTION_TRY()
        result = divide_(value_, den);
        EXCEPTION_CATCH_AND_RETURN(true, false)
    }

private:
    T value_;
    // used internally by private methods, allowed to throw
    double divide_(T const& num, T const& den) const
    {
        if (den > 0)
        {
            return num / den;
        }
        throw std::invalid_argument("denominator is zero");
    }
};

// C wrapper is not allowed to throw exceptions
double divide_numbers(double num, double den)
{
    EXCEPTION_TRY()

    number<double> n(num);
    double r = 0;
    n.divide_s(r, den);

    EXCEPTION_CATCH_AND_RETURN(true, false)
}

int main()
{
    bool success(false);
    double result(0);

    // Using C++ interface
    {
        number<int> n(10);
        // no error logged
        success = n.divide_s(result, 2);
        assert(success);
        // error logged, error code returned
        success = n.divide_s(result, 0);
        assert(!success);
    }
    // Using C interface
    {
        // no error logged
        result = divide_numbers(10, 2);
        // error logged
        result = divide_numbers(10, 0);
        // error logged
        float nan = 0;
        result = divide_numbers(nan / 0, 10);
    }
}

It’s simple and not ideal, but it did the job very well for myself and number libraries. Certainly, there are is a room for improvements. The logging mechanism is a simple one. It’s a good idea to add catch clauses for other types, even for int, especially if one has to deal with throw __LINE__; signals.

There is a lot of googlefindable articles and books one can buy. Here is the (incomplete) list of favourites guidelines:

Thanks to wonderful ACCU folks for a very interesting brainstorm on similar topic we had one day. Comments, improvements and bug reports would be greatly appreciated.

Traits of void resolved

Sunday, November 15th, 2009

It looks like I’ve got clarified status of the traits of void type. I posted my question to libstdc++ where Paolo Carlini kindly provided me what the bits I have been missing. Now, all the puzzles are in place:

[n1836], the specifications for the TR1 features mandates true for is_pod<void>, etc. Arguably this is a defect, which has been fixed in the ongoing work for the next standard, so-called C++0x.

The TR1 document in section 4.9 states:

8 It is unspecified under what circumstances, if any, is_pod::value evaluates to true, except that, for all types T:

is_pod<T>::value >=
   (is_scalar<T>::value || is_void<T>::value);

Given that, the bug report ID:458570 I submitted to Visual C++ 9.0 and it’s TR1 implementation on Microsoft Connect stays valid and according to what Stephan T. Lavavej confirmed in comments to my report, it’s been fixed in Visual C++ 10.0.

Paolo also added a note particularly important to programmers relying on C++ implementation by GCC compiler and libstdc++ library:

In general, we consider TR1 essentially frozen at this time and minimally maintained, consider that it was just an interim Technical Report

Here are references that are fundamental for the matter:

  • n1836 – Draft Technical Report on C++ Library Extensions
  • n2960 – Working Draft, Standard for Programming Language C++
  • Implementation of is_pod<T> and the rest of type traits by Boost.TypeTraits library.

Mission accomplished ;-)

Traits of void

Sunday, November 15th, 2009

Long time ago, I reported bug to Visual C++ 9.0 (Visual Studio 2008 SP1) complaining that has_trivial_destructor applied to void returns true (ID:458570). I also discussed it with folks on comp.std.c++ where, among quite different voices, Pete Becker writes:

[tr.meta.req]/8 in TR1 requires is_pod::value to be 1. n2857 is not a standard, and implementations of previous standards are not wrong for not doing what isn’t yet required of them.

and later concludes:

Under the current standard, using the name std::is_pod requires a diagnostic. So if you want to be literal, both compilers are “wrong”. Nevertheless, neither is really “wrong”, they just implement different non-standard versions of is_pod.

So, Visual C++ might actually not be wrong. Fair enough.

Today, I got back to this issue for a while a little extending my test program to use the type traits from both, TR1 and C++0x:

#include <iostream>
#include <tr1/type_traits>
int main()
{
using std::cout; using std::endl;
cout << std::tr1::is_pod<void>::value << endl;
cout << std::tr1::has_trivial_destructor<void>::value << endl;
cout << std::is_pod<void>::value << endl;
cout << std::has_trivial_destructor<void>::value << endl;
}

and compiled it with GCC 4.4.1:

$ g++ -Wall -pedantic -std=c++0x void.cpp
$ ./a.out
1
1
0
0

Now, my confusion has been raised to the power of 2. This is clearly a Polnische Wirtschaft or Czech movie or Turkish sermon

…let’s try to ask libstdc++ folks.

Inconsistent int64_t definition in GCC?

Sunday, November 15th, 2009

While compiling programs on Linux 32-bit with Comeau C/C++ 4.3.10.1 front-end and GCC 4.3.3 I encountered some problems using Boost Integer library, namely boost/cstdint.hpp header. Here we go:

If I first include sys/types.h (added with POSIX), directly or indirectly, and then include boost/cstdint.hpp in C++ program:

#include <sys/types.h>
#include <boost/cstdint.hpp>
int main()
{
    boost::int64_t a(0);
}

then it does not compile:

$ como -I/home/mloskot/dev/boost/_svn/trunk test1.cpp
MODE:non-strict warnings C++ noC++0x_extensions
"/home/mloskot/dev/boost/_svn/trunk/boost/cstdint.hpp", line 111: error: the
          global scope has no "int64_t"
    using ::int64_t;
            ^
"bad.cpp", line 5: error: namespace "boost" has no member "int64_t"
      boost::int64_t a(0);
             ^

Then, if stdint.h (added with C99) is included first (again, directly or indirectly), then the program compiles without any errors:

#include <stdint.h>
#include <boost/cstdint.hpp>
int main()
{
    boost::int64_t a(0);
}

It turns out that there is some amount of overlap in the stdint.h and sys/types.h headers. The issue is that the overlapped parts slightly differ. For the architecture, operating system and compilation toolset I use, both headers define int64_t type as follows:

typedef long long int int64_t;

However, the definition in sys/types.h header is guarded with different preprocessor condition testing __GLIBC_HAVE_LONG_LONG:

#  elif __GLIBC_HAVE_LONG_LONG
__extension__ typedef long long int int64_t;
#  endif

If I change sys/types.h replacing the clause with simple #else:

#  else
__extension__ typedef long long int int64_t;
#  endif

then the first variant of my program, the one including sys/types.h, does compile perfectly well.

Now, is this small difference a bug in the GNU C Library?
I’m going to try to confirm it.