Рассмотрите следующий код.
#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++?
Я пропускаю что-то?
Рекурсивный вызов rec ()
может изменить вектор, пока вы присваиваете ему значение.
Что произойдет, если вы замените
A[i].X = rec(idx+1);
на
int tmp = rec(idx+1);
A[i].X = tmp;
?
Также, просто резюмируем полезные комментарии: порядок вычисления операндов операции =
не указан, и поскольку вектор не был ' t предварительно выделен, несколько изменений размера могут произойти во время рекурсивного вызова rec ()
, таким образом делая недействительными любой итератор для значений в векторе.
Я получаю « * ошибка для объекта 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
на std :: vector
резервирует достаточно места для 10 элементов.Это предотвращает необходимость перераспределения вашей конкретной реализации rec
, и это исправляет ошибку на моей стороне.
Вы используете int i = A.size ()
И затем вы индексируете свою структуру как массив, но используя значение размера. Вам нужно уменьшить его на 1, например. A [i-1] .X = rec (idx + 1);
Ах, моя ошибка - я не учел вектор push_back.