Сегодня я наткнулся на одну очень не приятную багу. Рассмотрим следующий код.
#include <iostream>
#include <map>
using namespace std;
int main(){
map<int,int> m;
m[0]=m.size();
cout<<m[0]<<endl;
}
Как вы думаете, что выведет программа? Логично было бы 0. Ведь map изначально пуст. И Visual Studio 2008 express действительно выводит 0. Но вот если пользоваться g++ то на выходе окажется единица. Меня давно предупреждали в ЛКШ, что студия является компилятором неизвестного языка, но тут g++ повёл себя не адекватно. Если я правильно понимаю, то сначала должен вычисляться правый операнд оператора присвоить. Если я не прав, то объясните где. А если кто знает что-то подобное, то прошу поделиться опытом.
При обращении к элементу map через квадратные скобки, при его отсутствии, создается новый элемент map'a. Не знаю, как в MS C++, но в GNU это 100% так. На каком-то из недавних четвертьфиналов слетало много решений из-за неправильного обращения с map'ом. Чтобы обратиться к элементу map'a без риска создать новый элемент, нужно воспользоваться методом find().
Это Undefined Behaviour — не определен порядок вычисления. Можно почитать http://alenacpp.blogspot.ru/2005/11/sequence-points.html или http://en.cppreference.com/w/cpp/language/eval_order
Правильно написать или int id = m.size(); m[0] = id; или m.insert(pair<int, int>(0, m.size());
Спасибо за статью. Это как раз то что я искал.
Я стану на сторону g++.
Оператор "равно" грубо говоря принимает две ссылки: одну на то куда присваиваем, другую на то что присваиваем. Вы считаете логичным вычислять аргументы функции в обратном порядке? :)
Если бы порядок вычисления вообще был бы определен, то вычислять в обратном порядке было бы как раз логичнее: http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl
Это соглашение определяет в каком порядке класть аргументы в стек. Однако языки высокого уровня созданы как раз для того чтобы мы не клали руками в стек параметры, а код был читабельный и понимабельный. С человеческой точки зрения вычислять наоборот — странно :)
Если бы руками клали в стек, то вероятно в этом порядке же и вычисляли. А вообще если результат выполнения кода зависит от того, в каком порядке будут вычисляться аргументы вызываемой функций, то вероятно он уже не совсем читабельный и не совсем понимабельный =).
Ну вот как раз с человеческой точки зрения обратный порядок даже более правильно, если у нас например есть
a=b=c=d=e
, то намного проще было бы вычислять с конца — на каждом шаге вычисления мне не нужно помнить что там где произошло, я просто иду с конца и на каждом шаге помню всего три значения: левый операнд, правый операнд, значение присвоения; а при прямом порядке я должен запомнить результат выполнения на каждом шаге. Это конечно всё надумано и такие длинные равно признак гавнокодерства, речь лишь о том что проще для восприятия.Зря я начал этот тред, обсуждаем как правильнее говнокодить :)
А вообще, очевидно, что behaviour undefined и писать на олимпиадах такое — себе дороже.