Software: April 2010 Archives

 

April 10, 2010

One of the great things about C++ is that it turns simple typographical errors into an exercise in language hermeneutics. Consider, for example, the following code fragment:
1  #include <boost/shared_ptr.hpp>

3  class Clazz {
4  public:
5    int member_;
6  };


9  void bar(void)
10 {
11   boost::shared_ptr < Clazz > cl(Clazz());

13   cl->member_ = 9;
14 }

This code doesn't compile, however; you get the following error (reformatted a bit for presentation)

/tmp/cpp.cpp: In function 'void bar()':
/tmp/cpp.cpp:13: error: request for member 'member_' in 'cl', which is
of non-class type 'boost::shared_ptr ()(Clazz (*)())'

Now, I've cleaned this code up so that it isolates the error. The original code had the error buried in a sea of boost::variant and boost::bind error messages that took up about half a page. Even so, when I showed this code to a very experienced C++ and Boost programmer, he had the same reaction I (and one of my other colleagues had when we looked at the original code), namely, WTF. The problem with the code is that I've forgotten the new when constructing the object on line 11, but the compiler accepts that line just fine. However, the compiler chokes on line 13, not 11. Anyway, all three of us have the same reaction: sure line 11 is broken and the compiler should have complained, but given that it accepted it, how can this possibly screw up the perfectly unobjectionable reference to the member variable member_ in the class Clazz, indirected through a boost::shared_ptr.

At this point, we were seriously considering the possibility that it was a compiler bug, but after about 20 minutes of headscratching and trying different variants of the code, we finally paid attention to the error message that g++ was spitting out, which, when you actually look at it, is kind of clear. Despite appearances, this isn't a misinitialized boost::shared_ptr to Clazz. Instead, it's a shared function pointer to a function which takes a function pointer to a function returning Clazz (I think... I don't have a copy of c++decl handy).

As I said, this error appeared in some of my real code. It's probably not that common a mistake, but I've been working in Python as well as C++ and in Python you don't use new with constructors. In my experience this kind of error is a pretty common consequence of flipping back and forth between languages—my Python code is riddled with spurious (and luckily harmless) semicolons. And of course, C's (and by extension C++'s) inside-out syntax for function pointer declarations turns line 11 into legal, albeit obscure, syntax, letting the error trickle down to line 13, instead of just reporting a syntax error at the point where I actually made the mistake.

UPDATE: fixed various things in <> that render funny. Thanks to Hovav Shacham for pointing out the HTML errors. Grr.