Странное поведение STD :: уникальный - PullRequest
0 голосов
/ 04 октября 2018

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

Исключает все элементы, кроме первого, из каждой последовательной группы эквивалентных элементов из диапазона [first, last) и возвращает итератор за концом для нового логического конца диапазона.

vector<int> val = { 5,3,3,3,4};
unique(val.begin(), val.end());
for (auto it = val.begin(); it != val.end(); ++it)
    cout << *it << " ";

вывод: 5 3 4 3 4. не должен ли он возвращаться: 5 3 4 3 3.

и я подумал, что его нужно сначала отсортироватьпоэтому я делаю это:

vector<int> val = { 5,3,3,3,4};
sort(val.begin(), val.end());
unique(val.begin(), val.end());
for (auto it = val.begin(); it != val.end(); ++it)
    cout << *it << " ";

и вывод: 3 4 5 4 5.

Я обнаружил, что это действительно странно.ребята, вы знаете, почему?

Ответы [ 3 ]

0 голосов
/ 04 октября 2018

Единственная гарантия, которую вы получите от std::unique, - это то, что вы прописали: последовательность от начального итератора до возвращаемого итератора конца-в-конце соответствует указанной.Не указано, что происходит с резервными значениями в контейнере, начиная с возвращенного итератора конца цикла и продолжая до первоначального итератора конца последовательности.

Есть несколько других мелких деталей / гарантий / что это означает, чтоявляются частью std::unique контракта, но они здесь не актуальны.Суть в том, что единственное, что вы можете ожидать от std::unique, - это последовательность от начального итератора до возвращенного нового итератора прошлого, а все остальные значения в исходном контейнере не указаны.

Ваши наблюдения согласуются с std::unique вашей реализации с использованием семантики перемещения, которая для простых int s эквивалентна семантике копирования.Следовательно, оставшиеся значения в исходном итераторе являются копиями того, что было раньше.Это типичная реализация std::unique, но это не является обязательным требованием.

0 голосов
/ 04 октября 2018

cppreference на std::unique отвечает за это:

Относительный порядок элементов, которые остаются, сохраняется и физический размер контейнера не изменяется.Итераторы, указывающие на элемент между новым логическим концом и физическим концом диапазона, все еще разыменовываются, но сами элементы имеют неопределенные значения.За вызовом уникального обычно следует вызов метода стирания контейнера, который стирает неопределенные значения и уменьшает физический размер контейнера, чтобы соответствовать его новому логическому размеру.

Поэтому, чтобы действительно стеретьэлементы, вы также должны использовать vector::erase, пример которого приведен на связанной странице:

std::vector<int> v { 5, 3, 3, 3, 4 };
auto last = std::unique(v.begin(), v.end());
v.erase(last, v.end());
for (auto i : v)
    cout << i << "\n";

Вывод теперь

5
3
4

0 голосов
/ 04 октября 2018

Обратите внимание, что std :: unique

 "returns a past-the-end iterator for the new logical end of the range"

Чтобы увидеть новый диапазон, попробуйте:

auto new_end = std::unique(val.begin(), val.end());
for (auto it = val.begin(); it != new_end; ++it)
   cout << *it << " ";
...