Константные ссылки на диапазон элементов std::vector

Я хочу получить диапазон элементов из std::vector<MyClass> и сохранить их как константные ссылки, потому что я хочу только читать, но не изменять их.

#include <iostream>
#include <vector>

// a "large" user class
class MyClass {
public:
    int data;
    MyClass(int val) : data(val) {} 
};


int main() {
    // Initialize vector to MyClass objects
    std::vector<MyClass> myClass{1, 2, 3, 4, 5, 6, 7, 8};

    // Get const reference to element with index 0
    const auto &el = myClass[0]; 

    // Get const references to a range of elements
    const unsigned int start = 1, end = 4;
    // const auto &elRange = ???

    return 0;
}

Как я могу добиться чего-то подобного в c++17или ниже?

Вы можете использовать std::span, если можете перейти на C++20, или просто сохранить индексы в новом векторе.

wohlstad 06.09.2024 09:48

С какой проблемой вы столкнулись?

kiner_shah 06.09.2024 09:50

Похоже, вам просто нужна пара const_iterator: const auto elRangeBegin = myClass.cbegin() + 1; const auto elRangeEnd = myClass.cbegin() + 4;

Artyer 06.09.2024 11:06
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
3
106
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

std::span

const auto elRange = std::span(&myClass[1], &myClass[4]);

Я забыл упомянуть. у меня только с++17

Mathieu 06.09.2024 09:49

Напишите собственный класс представления, в котором вы не хотите использовать индексы и арифметику.

3CxEZiVlQ 06.09.2024 09:51

@Mathieu, тогда отредактируй свой вопрос и четко изложи это, чтобы все это заметили.

Marek R 06.09.2024 11:18

Для этого и создан std::span, но для этого вам понадобится C++20.

Если вы застряли на младших версиях C++, вы можете использовать boost::span. (Для включения в проект требуется 2 заголовка, вам не нужна вся библиотека повышения)

auto elements = boost::span<const MyClass>{myClass}.subspan(start, end-start);

Пример Godbolt на C++17

Ответ принят как подходящий

Я хочу получить диапазон элементов из std::vector и сохранить их как константные ссылки, потому что я хочу только читать, но не изменять их.

Лучше всего использовать std::span , для которого требуется поддержка C++20.

В противном случае вы пишете для этого простой SimpleSpan класс. Так же просто, как:

// A simple span-like class for C++17
template<typename T>
class SimpleSpan 
{
   T* data_;
   std::size_t size_;

public:
   constexpr SimpleSpan(T* data, std::size_t size) : data_{ data }, size_{ size } {}

   constexpr T& operator[](std::size_t index) { return data_[index]; }
   constexpr T& operator[](std::size_t index) const { return data_[index]; }

   constexpr T* begin() { return data_; }
   constexpr T* end() { return data_ + size_; }
   constexpr T* begin() const { return data_; }
   constexpr T* end() const { return data_ + size_; }

   constexpr std::size_t size() const { return size_; }
};

и просто

// Get const references to a range of elements using our SimpleSpan
const unsigned int start = 1, end = 4;
SimpleSpan<const MyClass> elRange(&myClass[start], end - start);

Посмотрите живую демонстрацию

Разве нам не нужно писать деструктор этого класса? Поскольку SimpleSpan имеет необработанный указатель в качестве члена

Mathieu 06.09.2024 10:07

@Матье, класс не владеет данными и не управляет ими. Что бы вы поместили в предложенный вами деструктор?

wohlstad 06.09.2024 10:12

@Mathieu Std::span/ SimpleSpan — это представление непрерывной последовательности объектов, не являющееся владельцем. Он не управляет никакими ресурсами напрямую. Он спроектирован так, чтобы быть простым и легким, без необходимости индивидуального управления ресурсами. Поэтому нет необходимости в правиле 3/5!

JeJo 06.09.2024 10:13

То же самое касается ссылок/указателей/представлений векторов. Вам не следует их где-либо хранить (просто используйте их локально). Одна модификация базового вектора может привести к перераспределению, и тогда ваше представление перестанет быть действительным.

Pepijn Kramer 06.09.2024 11:38

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