2010-03-03
When new features collide with old syntax
My C++ times are over. But Roker keeps on feeding me with input. And I could not let this one go by unnoticed.
To make it short, what do you think does the following program print?
#include <iostream>
struct X { };
class Y {
public:
Y (const X& x) {
std::cout << "fnord" << std::endl;
}
};
int main() {
Y d(X());
return 0;
}
At first sight it looks like everything is ok. We know that references to temporaries must be const, which is the case here. So we think, d is going to be a Y object which was initilized with a temporary X object. In this case, the program should output "fnord".
But it doesn't. Instead it prints nothing. Mysterious you think? So did I. So I started debugging the issue while Roker was giggling. So, if d is not a Y object, what is it then? Let's ask the compiler and the C++ runtime:
#include <typeinfo>
//...
int main() {
Y d(X());
std::cout << typeid(d).name() << std::endl;
return 0;
}
The program now prints "F1YPF1XvEE". Hmm, I can not decrypt this, can you? We need to demangle the name in order to see it's real C++ nature:
$ c++filt -t F1YPF1XvEE
Y ()(X (*)())
Who can decrypt this? If you can't, here is a howto on reading C type declarations, because the unfamiliar syntax for function types is a C heritage. And what does this type mean after all? It means, that d is a function which returns a Y object and expects a pointer to a function which returns a X object and expects nothing. Got it? If not, here is how I would write it, in case I would need such a type:
#include <iostream>
#include <typeinfo>
struct X { };
class Y { /*...*/ };
typedef X (Inner)();
typedef Y (Outer)(Inner);
int main()
{
Outer d;
std::cout << typeid(d).name() << std::endl;
return 0;
}
This program prints Y ()(X (*)()) which is the type of d from the original program.
Ok, so now we know, what the program does. It declares a function. That's why there is no X object ever created. So, although the code could mean what we originally intended, the compiler chooses to understand something else, which is also possible due to the C syntax rules. Although I still don't know what function declarations inside other functions are good for, the compiler again prefers them. Anyway, what's the C way of removing ambiguity from syntax? Right, it's parantheses:
//...
int main()
{
Y o((X()));
std::cout << typeid(o).name() << std::endl;
return 0;
}
Now, the program prints "fnord" and "1Y" which is the mangled name for the type Y.
To sum it up, this is yet another example for why I consider the C heritage to be a major source of trouble for C++ developers. The C syntax was never designed for temporary variables and combining both yields to what we have seen here: ambiguity, ugly workarounds and surprise and furstration for the developer. Don't get me wrong, though. I still think that C++ could hardly have been made better given the design goals which where taken those days. I truly have a love-hate for that language.
2009-11-09
C++ Pitfalls
As I do no C++ hacking at ETH I have not stumbled upon new input for this blog on my own. So I am very happy that Roker keeps on feeding me.
Today he pointed me at Cay Horstmann's list of C++ pitfalls. Some of the issues have already been covered here but some haven't. I recommend reading it to every C++ developer as this takes less time than learning it the hard way by debugging code. Have fun.
Concerning the iterator issues Cay provides a Safe STL implementation which is supposed to be used as a drop in replacement for the STL during development. It adds state and knowledge about the owner to iterators and uses this information to do runtime checks. If you accidently use your iterators in a wrong way you end up with a comprehensive runtime error instead of a segfault "deep in the bowels of STL code".
I haven't tested Safe STL. If anybody did feel free to send me your experience. I would be glad to blog about it.
2009-11-09
Catching Integer Overflows in C
abs may return a negative number. Comforting to know that C++ inherited this behaviour....
2009-08-22
The Safe Bool Idiom
Operator overloading is considered a major C++ feature. But as so often with C++ this feature sometimes clashes with other language properties.
Roker pointed me to an article about
the safe bool idiom
where the author elaborates on why a simple operator bool is not
satisfying if you want to be able to use an object within a bool context. Have
fun...
2009-07-09
feature collision
One thing the C++ community is pretty proud of is that, in contrast to C, C++ supports const correctness. Turns out that const correctness clashes with STL containers.
Today Roker pointed me to a poor guy from #c++@freenode with the following problem:
#include <iostream>
#include <list>
typedef std::list<int> list_t;
list_t::const_iterator find_first_odd(const list_t & list)
{
for (list_t::const_iterator i = list.begin(); i != list.end(); ++i)
{
if (*i % 2 != 0) return i;
}
return list.end();
}
int main()
{
list_t list;
list.push_back(2);
list.push_back(3);
list.push_back(4);
list_t::const_iterator odd_i = find_first_odd(list);
if (odd_i != list.end())
// Error. Can not use const_iterator with 'std::list::erase'
list.erase(odd_i);
return 0;
}
For the sake of const correctness the function find_first_odd
expects a constant reference to the list because it is not going to modify it.
But as a result the function can only return a const_iterator,
because there is no way to get a non-const iterator from the
constant list.
So the caller of find_first_odd ends up with a
const_iterator which is useless for modifying operations such as
erase. And for him it is also impossible to turn the
const_iterator into a non-const iterator. The two
types have no relation to each other, so casting does not work. And there are
no conversion functions in the STL either. So the only way out here is to
sacrifice const correctness and pass a non-const reference to
find_first_odd.
According to Roker nobody on #c++ had a better solution. And according to Scott Meyers' article Three Guidelines for Effective Iterator
Usage there is none. const_iterators can not be easily transformed
into iterators. What you can do is nasty and rather inefficient.
Here it comes:
template <class Container>
typename Container::iterator convert(typename Container::const_iterator in, Container& container)
{
typename Container::iterator out(container.begin());
std::advance(out, std::distance<typename Container::const_iterator>(out, in));
return out;
}
If the container does not support random access, this conversion is O(n).
Furthermore it can only be done, if the container object is at hand. Finally
note, that this function violates const correctness, because the container object
which is not altered by the function is not passed as const&.
The reason is that the begin() function of a constant container
returns a const_iterator which you can not convert into the output
non-const iterator. In case you are confused, try this illustration.
2009-06-22
C++ truths
Since I am at the ETH in Zurich I haven't used C++. The reason is simply the fact that I haven't encountered any problem for which C++ is the tool of choice. That's why there has been almost no input to this category from me.
But there are others who blog about C++. So I will be satisfied with passively following the C++ topic and refering to them.
Today's featured C++ blog is C++ thruths from Sumant Tambe. Hmm, infinite regress, yummy. ;-)
Thank you Roker
2009-05-20
the longest suicide note in history
I am not alone with my estimation of C++ being a dead end. Today Roker pointed me to an article from Allan Kelly about the future of C++. Here is my favourite quote:
[the C++ 0x standard will be] the longest suicide note in history.
Other languages do better. Python 3.0 and Perl 6 are not downward compatible and in both cases I think this is a good idea. Why is this impossible for C++?
2009-03-30
git
Rico und ich haben beim Chaostreff Rheintal und dem net culture lab Dornbirn einen Vortrag über das Versionsverwaltungssystem git gehalten.
Links zu den Folien und den Aufzeichnungen gibt es hier.
2009-02-20
moving on
I am a PhD student at ETH Zurich now. Besides other cool infrastructure the ETH provides blogs for associates. No doubt, I had to try out.
It's a WordPress, so I am leaving the nanoblogger paradigm of static page content. What I can get is interaction through reader comments and trackbacks. But I'm also a target for spam and crackers now. We'll see...
Anyway, here is copton's ETH blog. For the time being new posts will go there.
2009-02-15
C Traps
Quite a time ago Andrew König has written a book about C traps and pitfalls. Today, Roker pointed me on an earlier technical report which was the basis of the book.
Although some things are different with C++, I recommend everybody to read at least the report. Otherwise you surely will stumble on those items sooner or later.

