Странное поведение std :: find, возвращает true, когда элемент не находится в векторе

Выглядит очень прямолинейно, типичное использование std :: find

for ( auto element : generic->vec() )
        LOG << element;

    LOG << channel;

    if ( !gen->vec().empty() ) {

        if(std::find(generic->vec().begin(), generic->vec().end(), channel) != generic->vec().end()){

            LOG << "Found";
            ;// Found the item
        } else {

            LOG << "Not Found";
            return false;

        }
}

Проверьте файл журнала

2018-11-08, 09:37:18 [INFO] - [140455150589696] - 1
2018-11-08, 09:37:18 [INFO] - [140455150589696] - 2
2018-11-08, 09:37:18 [INFO] - [140455150589696] - 4
2018-11-08, 09:37:18 [INFO] - [140455150589696] - 12
2018-11-08, 09:37:18 [INFO] - [140455150589696] - 40
2018-11-08, 09:37:18 [INFO] - [140455150589696] - Found

Вектор содержит 1,2,4,12, а входящее значение, которое мы хотим проверить, если оно принадлежит вектору, равно 40. std :: find возвращает true, что он найден.

Метод vec () возвращает массив элементов uint64_t:

std::vector<uint64_t>  vec() const {
  return vec_;
}

Когда я создаю локальный вектор, т. Е.

auto tmp = generic-> vec (),

код работает.

Где ошибка в моем коде? Я ожидал бы получить «Не найден» при проверке, принадлежит ли 40 к [1,2,4,12].

Всего 2 ответа


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

Простое решение - вернуть вектор по ссылке :

std::vector<uint64_t> const&  vec() const { ... }

Подпись std::vector<uint64_t> vec() const означает, что возвращается rvalue (копия vec_ ). Это прекрасно, если вы не сравниваете ссылки на элементы vec() от разных вызовов. Пример:

auto v1 = vec();
auto v2 = vec();

v1.begin() != v2.begin(); // Don't do that - UB

Это то же самое, что и

vec().begin() != vec().begin(); // Again, UB

Благодаря @Aconcagua за указание, что сравнение - это неопределенное поведение, в первую очередь, см. Также этот вопрос .

Такие вещи могут быть трудно обнаружить, когда вы привыкли к диапазону, основанному на циклах, например

for (const auto& value : vec()) { /* ... */ }

Это не проблема, но под капотом этот фрагмент расширяется таким образом, что возвращаемое значение vec() привязано к переменной auto&& и любые вызовы методов *begin/*end ссылаются на один и тот же объект.

Короче говоря: привяжите возвращаемое значение к переменной перед запросом итераторов или измените подпись ov vec() , чтобы она возвращала ссылку, а не копию.


Есть идеи?

10000