set_union получил неправильный результат, когда я назвал его дважды - PullRequest
3 голосов
/ 06 мая 2019

эта проблема смущала меня много часов, Помогите мне, пожалуйста! первый раз, когда я вызываю set_union, результат правильный, но во второй раз я вызываю его, результат неправильный, см. код:

std::vector<int> set1{ 1, 2, 3, 4, 5, 6 };
std::vector<int> set2{ 4, 5, 6, 7, 8 };
std::vector<int> result{};

std::set_union(std::begin(set1), std::end(set1),
    std::begin(result), std::end(result), 
    std::back_inserter(result));  
// result is 1 2 3 4 5 6

std::back_insert_iterator< std::vector<int>> back2 =
    std::set_union(std::begin(set2), std::end(set2), 
        std::begin(result), std::end(result), 
        std::back_inserter(result)); 

Я отлаживаю приведенный выше код, получаю такой результат:

[0] 1   int
[1] 2   int
[2] 3   int
[3] 4   int
[4] 5   int
[5] 6   int
[6] 1   int
[7] - 572662307 int
[8] - 572662307 int
[9] - 572662307 int
[10] - 572662307    int
[11] - 572662307    int
[12]    4   int
[13]    5   int
[14]    6   int
[15]    7   int
[16]    8   int

Ответы [ 2 ]

3 голосов
/ 06 мая 2019

Результирующий диапазон не может перекрываться ни с одним из входных диапазонов. https://en.cppreference.com/w/cpp/algorithm/set_union

Почему бы тебе не использовать это?

 std::set_union(std::begin(set1), std::end(set1), 
    std::begin(set2), std::end(set2), 
    std::back_inserter(result)); 
2 голосов
/ 06 мая 2019

У вас здесь неопределенное поведение.Когда вы передаете итераторы в result в качестве входных и выходных параметров в std::set_union, запись в выходной итератор делает недействительными все входные итераторы.Это связано с разметкой памяти std::vector - для записи в нее может потребоваться переместить все ее данные в новое место в памяти, если емкость не может содержать новый элемент, поэтому ссылки / указатели / итераторы ссылаются на исходную памятьместоположения больше не могут использоваться.

Вы хотите сохранить результат в новом контейнере, например,

std::vector<int> out;
std::set_union(std::begin(set2), std::end(set2), 
    std::begin(result), std::end(result), 
    std::back_inserter(out));

Также обратите внимание, что для первого вызова std::copy является более подходящималгоритм (или присваивание result = set1;).

...