Странное поведение std :: find, возвращает true, когда элемент отсутствует в векторе - PullRequest
0 голосов
/ 08 ноября 2018

Выглядит очень простой случай, типичное использование 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 ]

0 голосов
/ 08 ноября 2018

Подпись std::vector<uint64_t> vec() const подразумевает, что возвращается значение (копия 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(), чтобы она возвращала ссылку, а не копию.

0 голосов
/ 08 ноября 2018

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

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

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