С++ STL map:: operator [], выполненный при удалении записи

std::map<int,int> bar;

int foo(int key)
{
  bar.erase(key);
  return 1;
}    

int main()
{
  bar[0] = foo(0);
  return 0;
}

Этот код скомпилирован с ошибкой GCC 4.8 segs при проверке использования памяти с помощью электрического заграждения.

LD_PRELOAD=libefence.so.0.0 ./a.out

Проблема возникает из-за того, что компилятор генерирует код, который начинает выделять новую запись на карте, а затем выполняет foo(), чтобы получить значение, помещенное в bar[0]. При запуске foo() запись уничтожается, и код, наконец, заканчивается записью в нераспределенной памяти.

Способ упорядочения операций зависит от реализации компилятора или задан ли он текущим стандартом С++?

Ответы

Ответ 1

В стандарте (§1.9 15) указывается, что оценка двух операндов двоичным оператором не имеет значения (если только в некоторых конкретных случаях):

За исключением тех случаев, когда отмечено, оценки операндов отдельных операторов и подвыражения отдельных выражений не подвержены.

Это означает, что он не гарантирует, что одна сторона операции присваивания оценивается перед другой, и на самом деле поведение undefined зависит от порядка этих нечеловеческих операций.

Это также справедливо для порядка оценки аргументов функции.

Вам нужно разбить свое назначение на две части:

int result = foo(0);
bar[0] = result;