почему код вызывает ошибку сегментации?

#c 11

#c 11

Вопрос:

Ниже приведен код:

 vector<set<int>> sets;
set<int> myset{ 3, 5, 8, 2, 10, 9, 7, 15 };
set<int> newSet{ *myset.begin() };
sets.push_back(newSet);
set<int>::iterator it = myset.begin();
it  ;
for (; it != myset.end(); it  )
{
    for (vector<set<int>>::iterator it1 = sets.begin(); it1 != sets.end(); it1  )
    {
        set<int> newSet1(*it1);      //LINE1
        sets.push_back(newSet1);     //LINE2
        it1->insert(*it);            //LINE3
    }

}
 

Во время первого ввода во второй цикл for, после LINE2 , it1 становится НУЛЕВЫМ, поэтому LINE3 вызывает segmentation fault . Почему после LINE2 , it1 исчез?

LINE2 копирует newSet1 в векторные наборы. Будет ли он копировать весь набор или только адрес newSet1 ?

Ответ №1:

Давайте возьмем подмножество вашего кода:

 std::vector<T> sets;
for (auto it = sets.begin(); it != sets.end(); it  )
    sets.emplace_back();
 

Приведенный выше код демонстрирует неопределенное поведение, потому что мы модифицируем вектор, а затем ожидаем, что итераторы sets все еще действительны.

В частности, итераторы станут недействительными при выполнении insert() и size() == capacity() .

По поводу вашего другого вопроса:

СТРОКА 2 копирует newSet1 в наборы векторов. Будет ли он копировать весь набор или только адрес newSet1?

Он вызовет конструктор копирования std::set<T> , и вы получите копию набора, который вы передали в качестве аргумента для push_back() вызова.

Ответ №2:

Push_back изменяет наборы, поэтому it1 больше не является надежным. Push_back копирует всю запись в вектор.

Доступ к вектору через индекс (например, sets[2] ) будет работать, но границы не проверяются, поэтому перед доступом убедитесь, что индекс находится в пределах диапазона.

Комментарии:

1. Это слишком жутко. 🙁 Предполагается, что push_back создает только копию newSet1. Почему он уничтожает newSet1?

2. Это не так. Это не уничтожает запись, которая помещена в вектор.

3. @John это не уничтожает newSet1 , а делает недействительным it1 . Это происходит после push_back того, как итератор it1 указывает на неправильное местоположение, и это вызывает неопределенное поведение, в вашем случае segfault.

4. it1 ненадежен, потому что push_back может полностью изменить вектор. (Он может быть скопирован в другую область памяти для обработки более длинного массива. Бесплатных обедов нет даже в STL.)

5. Что мне нужно, так это изменить вектор во время итерации вектора. Нет никакого способа сделать это с помощью итератора, верно? Как насчет использования «для цикла диапазона»? например, ‘for(auto e : vec) {std::set e1(e); vec.puch_back(e1); }’. Будет ли это работать?