C++ 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, вызывает ошибку при проверке использования памяти с помощью электрического ограждения.

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

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

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

1 ответ

Решение

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

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

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

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

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

int result = foo(0);
bar[0] = result;
Другие вопросы по тегам