Должен ли я вернуть gsl::span<const T> вместо const std:: vector<T>&

У меня есть класс с членом std:: vector и функцией-членом, возвращающей константную ссылку на этот вектор.

class demo {
public:
    //...

    const std::vector<int> & test() const {
        return iv;
    }

private:

    std::vector<int> iv;
};

Я планирую изменить тип члена на другой массив, такой как тип контейнера, с достаточной функциональностью и меньшим объемом памяти (например, std:: эксперимент:: dynarray, std:: unique_ptr). Поэтому я подумал, что было бы хорошей идеей не возвращать реальный контейнер как константную ссылку, а возвращать представление элементов в виде gsl:: span.

class demo {
public:
    //...

    gsl::span<const int> test() const {
        return iv;
    }

private:

    std::vector<int> iv;
};

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

demo d;

std::cout << (d.test().begin() == d.test().begin()) << "\n";
std::cout << (d.test().end() == d.test().end()) << "\n";

for( auto it = d.test().begin(), end = d.test().end(); it != end; ++it )
    std::cout << *it << "\n";

Это печатает 0 0 и затем терпит крах, потому что проверить это! Конечно, диапазон, основанный на цикле, работает, но этот цикл действителен и поэтому должен также работать как положено. Я ожидал, что все диапазоны из одного и того же диапазона одного и того же контейнера равны, так что итераторы любого из этих диапазонов сравнимы (контейнер, конечно, не изменен). Конечно, есть веская причина, почему это не так.

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

2 ответа

Ты используешь iterator временный, так что ваш iterator стать инвалидом сразу после воздействия.

Вы можете использовать следующее:

auto&& view = d.test();
for (auto it = view.begin(), end = view.end(); it != end; ++it) {
    std::cout << *it << "\n";
}

Так что ответ НЕТ, потому что он нарушает код, который был действителен раньше.

Другие вопросы по тегам