I'm working on a project right now where we're replacing a Qt interface written in Python (PyQt) with C++ Qt as it's way too slow (interface is really laggy), and other than things like having to occasionally delete objects manually (often, if you just add a widget to a layout, Qt does the deletion for you), it's pretty much a 1-1 mapping.
We're also replacing core op-graph and geometry processing from Python to C++, and again it's close to 1-1 - there's a bit of overhead in the loops - in our coding style we're caching begin iterators on the line before the loop, but other than that it's very close.
And the speed of the app is so much faster it's not even funny.
python:
for face in mesh.faces():
faceCentre = Point()
for v in face.vertices():
faceCentre.add(mesh.getPoint(v))
faceCentre.div(len(face.vertices()))
C++:
std::vector<Face>::const_iterator itFace = mesh.getFaces().begin();
for (; itFace != mesh.getFaces().end(); ++itFace)
{
const Face& face = *itFace;
Point faceCentre;
std::vector<unsigned int>::const_iterator itVertex = face.vertices.begin();
for (; itVertex != face.vertices().end(); ++itVertex)
{
const unsigned int& pointIndex = *itVertex;
faceCentre += mesh.getPoint(pointIndex);
}
faceCentre /= (float)face.vertices().size();
}
So the C++ is longer, but you've got braces, and the references to the Face and unsigned int pointIndex are placed as a local variables, which makes debugging much easier - they could be inlined.
It's possible to get that down even more using more modern C++ - using auto variables and not declaring the start iterator on it's own line.
So yes, counting braces, it can be a lot more lines, but if you don't count braces, it's generally not that much more.
I guess what I'm asking is, why are you declaring the start iterator on its own line? What benefit does it have? Or does is just make the for loop line shorter?
Also, as of C++11 you can do this:
for(const Face& face : mesh.getFaces()) {
Point faceCentre;
for(size_t pointIndex : face.vertices())
faceCentre += mesh.getPoint(pointIndex);
faceCentre /= static_cast<float>(face.vertices().size());
}
We sometimes hoist the end iterator as well, as often g++ can't optimise out the call to .end() each iteration - it can if there's a ref to a const item and you call end() on that const ref, but otherwise, it generally doesn't as it can't guarantee the item hasn't been modified.
We're still stuck with CentOS 5.4, so g++ 4.1 for us as that's what we've got to deploy to (although we use ICC for production builds, building off the g++ 4.1 standard headers)...
Basically, we want top possible speed - if that means the code's a bit more verbose than it can be, so be it.
We're also replacing core op-graph and geometry processing from Python to C++, and again it's close to 1-1 - there's a bit of overhead in the loops - in our coding style we're caching begin iterators on the line before the loop, but other than that it's very close.
And the speed of the app is so much faster it's not even funny.