Различие в поведении (GCC и Visual C++)

Рассмотрите следующий код.

#include 
#include 
#include 

struct XYZ { int X,Y,Z; };
std::vector A;

int rec(int idx)
{

   int i = A.size();
   A.push_back(XYZ());
   if (idx >= 5)
     return i;

   A[i].X = rec(idx+1);

   return i;
}

int main(){
  A.clear();
  rec(0);
  puts("FINISH!");

}

Я не мог выяснить причину, почему код дает отказ сегментации на Linux (используемый IDE: Код:: Блоки), тогда как в Windows (IDE использовал: Visual C++), это не делает.

Когда я использовал Valgrind только для проверки, какова на самом деле проблема была, я получил этот вывод.

Я добрался Invalid write of size 4 в четырех различных местах. Затем, почему код не отказал, когда я использовал Visual C++?

Я пропускаю что-то?

12
задан Peter Mortensen 9 May 2010 в 20:22
поделиться

3 ответа

Рекурсивный вызов rec () может изменить вектор, пока вы присваиваете ему значение.

Что произойдет, если вы замените

A[i].X = rec(idx+1);

на

int tmp = rec(idx+1);
A[i].X = tmp;

?

Также, просто резюмируем полезные комментарии: порядок вычисления операндов операции = не указан, и поскольку вектор не был ' t предварительно выделен, несколько изменений размера могут произойти во время рекурсивного вызова rec () , таким образом делая недействительными любой итератор для значений в векторе.

17
ответ дан 2 December 2019 в 19:30
поделиться

Я получаю « * ошибка для объекта 0x300180: неверная контрольная сумма для освобожденного объекта - объект, вероятно, был изменен после освобождения. * » при запуске этого кода.

Насколько я помню, A [i] .X = rec (idx + 1) имеет три точки последовательности. Когда operator [] вызывается в A, когда вызывается rec и в конце. Но порядок первых двух не указан. Итак, если g ++ сначала вычисляет A [i] , а затем вызывает rec (idx + 1) , тогда, когда rec возвращает ссылку, возвращенную A [i] могло стать недействительным из-за перераспределения внутренней памяти вектора. В VC ++ он может сначала оценивать rec (idx + 1) , поэтому все вызовы push_back выполняются заранее, что означает A [i] вызовы относятся к правильному блоку памяти. В качестве альтернативы, он может делать то же самое, и у вас просто не происходит segfault ... это одна из проблем неопределенного поведения.

Изменение std :: vector A; на std :: vector A (10); резервирует достаточно места для 10 элементов.Это предотвращает необходимость перераспределения вашей конкретной реализации rec , и это исправляет ошибку на моей стороне.

1
ответ дан 2 December 2019 в 19:30
поделиться

Вы используете int i = A.size ()

И затем вы индексируете свою структуру как массив, но используя значение размера. Вам нужно уменьшить его на 1, например. A [i-1] .X = rec (idx + 1);

Ах, моя ошибка - я не учел вектор push_back.

0
ответ дан 2 December 2019 в 19:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: