I haven't dealt with the exact module you're using, but from the documentation:
http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_descriptor_matchers.html
It seems that the second call is swapping the training with the query, and hence can give you a different set of results. This is also hinted at by the naming of matches12 changing to matches21 -- it's not two-way association, but a direction association.
You see this in training large datasets in machine learning where you're results training one subset of the data gives a better performance than training on a different subset of the data. I don't know how the two matches are used after the step you've written but I imagine it allows for either choice of best training, or for capturing better covariance information from the data.
Euclidean distance is the same in both directions, but the ordering of the double vector changes and hence the structure of association changes between the two calls (unless descriptors1 == descriptors2, which would form a symmetric matrix and then probably be useless to repeat).
Posting the uses of matches12 and matches21 later in the codebase would probably also clarify the exact reason for having both direction associations.
Hopefully this gives a starting place for understanding the repeated call.
* EDIT *
I looked over the source code you provided a link to and in answer to your question, the distance IS the same between two points, but the closest point of a specific point (point A) to another particular point (point B) is not necessarily an invert-able statement. Thus B may be the closest point to A, but A may not be the closest point to B.
As Frédéric's post shows graphically, it's not that the Euclidean distance changes between 2 points but rather that the point with the closest Euclidean distance can change when changing the perspective of the comparison. Thus cross-checking can validate point which share closest point relationships (A is closest to B and B is closest to A).
Your intuition that this is not the best approach (with large numbers of points) is correct though, as a more complicated approach could find all such relationships in O(N*ln(N)) time instead of O(N^2) time -- especially a heuristic driven search. But for a (relatively) small number of points the expected performance gain would be negligible and the implementation would be (much for good improvement) more complicated.
knnMatch(A,B)
should be the same ofknnMatch(B,A)
don't you find ? – Daric