Почему он показывает недопустимую ячейку памяти при сортировке вектора после слияния?

#c #stl

#c #stl

Вопрос:

Я попытался отсортировать новый вектор после слияния двух векторов, вот такой код,

 #include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>

using namespace std;

void vec_output(vector <int> vec_input)
{
    
    for (int i = 0; i < vec_input.size(); i  )
    {
        cout << vec_input[i] << ' ';
    }
    cout << endl;
}

int main(){
    vector <int> v1{2,3,1};
    vector <int> v2{5,4,6};
    vector <int> v3;
    set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
    sort(v3.begin(), v3.end());
    vec_output(v3);
    return 0;
}
 

Однако он показывает ошибку: Exception has occurred. Segmentation fault , я знаю, что это может быть вызвано доступом к неизвестной памяти, но как?

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

1. проверьте: en.cppreference.com/w/cpp/algorithm/set_union , вам необходимо указать std::back_inserter(v3) в set_union()

2. Помимо этой проблемы, std::set_union работает с отсортированными диапазонами. Ваш вектор v1 не отсортирован. Поведение не определено. Также бессмысленно вызывать std::sort результирующее объединение, поскольку оно уже будет отсортировано.

3. Вы читали документацию ? Подсказка: std::back_inserter(v3) . Кроме того, неудивительно, .begin() что в пустом векторе получается что-то, что действительно только для сравнений .end() , но не для (попыток) разыменования. И последнее, но не менее важное: using namespace std; это антипаттерн, пожалуйста, не делайте этого.

4. @AndrejPodzimek Я собираюсь удвоить рекомендацию, чтобы избежать using namespace std . Вместо этого просто извлеките нужные вам фрагменты, например using std::vector .

5. std::set_union() , как и ряд других алгоритмов, предполагает, что последний аргумент является итератором с возможностью разыменования. v3 не имеет элементов, поэтому v3.begin() будет равно v3.end() и разыменование его (для записи значения через него) дает неопределенное поведение. Используйте std::back_inserter(v3) вместо этого — это создает итератор, к которому будут добавляться элементы v3 .

Ответ №1:

Проблема в том, что v3 пусто, поэтому запись v.begin() в качестве последнего аргумента set_union невозможна. Вы должны использовать back_inserter как:

 set_union(v1.begin(), v1.end(), v2.begin(), v2.end(),  std::back_inserter(v3));
 

std::back_inserter Вернет итератор вывода back_insert_iterator , который будет использоваться v3.push_back для добавления / возврата элементов v3 .

Кроме того, из документации std::set_union:

Элементы сравниваются с помощью operator<, и диапазоны должны быть отсортированы по одному и тому же.

(Выделение мое)

Также обратите внимание, что после использования set_union вам не нужно использовать std::sort on v3 .

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

1. Это не полная история. Если set_union вызывается для диапазонов, которые не отсортированы ( v1 и v2 ), поведение не определено.

2. Вы также должны добавить, что сортировка вывода set_union не требуется.

3. Нет необходимости в итераторе вставки, если `v3` инициализирован с правильным размером.