我想从 a 中获取一系列元素std::vector<MyClass>并将它们存储为const-ref,因为我只想读取它们但不想修改它们。

#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 或更低版本中实现这样的事情?

2

  • 1
    如果您可以升级到 C++20,则可以使用它,或者只是将索引存储在新向量中。


    – 


  • 1
    听起来你只是想要一对const_iterators:const auto elRangeBegin = myClass.cbegin() + 1; const auto elRangeEnd = myClass.cbegin() + 4;


    – 


最佳答案
3

我想从 std::vector 中获取一系列元素并将它们存储为 const 引用,因为我只想读取它们但不想修改它们。

最好的方法是使用,这需要支持。

否则,你可以编写一个简单的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);

4

  • 我们不必编写此类的析构函数吗?因为SimpleSpan有一个原始指针作为成员


    – 

  • 2
    @Mathieu 该类不拥有或管理数据。您会在建议的析构函数中放入什么?


    – 

  • 5
    @Mathieu std::span/ SimpleSpan 是连续对象序列的非拥有视图。它不直接管理任何资源。它设计得简单轻量,避免了自定义资源管理的需要。因此,不需要 3/5 规则!


    – 


  • 3
    这就是向量上的引用/指针/视图的问题。您不应将它们存储在任何地方(仅在本地范围内使用它们)。对底层向量的一次修改可能会重新分配,然后您的视图将不再有效。


    – 

这就是用途,但您需要 C++20 来实现它。

如果您使用较低的 C++ 版本,则可以使用。 (它需要 2 个标头才能包含在项目中,您不需要整个 boost 库)

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

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

3

  • 3
    我忘了说了。我只有 c++17


    – 

  • 如果您不想使用索引和算术,请编写自己的视图类。


    – 


  • @Mathieu 然后编辑你的问题并在那里清楚地说明这一点,以便每个人都会注意到这一点。


    –