给定 myvector.start() 和 myvector.end(),我想在不复制数据的情况下创建 myvector

Given myvector.start() and myvector.end() I want to create a read-only subset of myvector without copying the data. Is this possible, and how?

本文关键字:myvector 复制 数据 情况下 创建 start end 给定      更新时间:2023-10-16

给定myvector.start()和myvector.end() 我想在不复制数据的情况下创建myvector的只读子集

这可能吗,如何?

#include <iostream>
#include <vector>
using namespace std;
template <class T> void print_vector(const vector<T> &v) {
    for(size_t i = 0; i < v.size(); ++i) std::cout << v[i] << " ";
    std::cout << std::endl;
}
int main() {

首先,我创建向量。

    vector<double> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    print_vector(data); // 1 2 3 4 5 6 7 8 9 10

然后我想要一个子集。但我认为这是复制品。

    // Does this make a copy or not? I don't want to make a copy.
    const vector<double> subset1(data.begin() + 3, data.end() - 3);
    print_vector(subset1); // 4 5 6 7

这种方法怎么样?

    // Another approach. Questions:
    // - Would something like this be a good alternative if I really don't want a copy?
    // - How would the performance of this be compared to a normal STL container?
    // - Is there an existing implementation of a container that does something like this, maybe a boost class?
    class SubsetType {
    public:
        SubsetType(const vector<double>::iterator &start, const vector<double>::iterator &end) { begin_ = start; end_ = end; }
        vector<double>::iterator begin() { return begin_; }
        vector<double>::iterator end() { return end_; }
        double operator[](vector<double>::size_type i) { return *(begin_ + i); }
        vector<double>::size_type size() { return end_ - begin_; }
    private:
        vector<double>::iterator begin_, end_;
    };
    SubsetType subset2(data.begin() + 3, data.end() - 3);
    for(size_t i = 0; i < subset2.size(); ++i) std::cout << subset2[i] << " ";
    std::cout << std::endl; // 4 5 6 7

或者是声明所有函数的解决方案,例如 f(const vector::iterator &start, const vector::iterator &en)。STL算法就是这样做的,对吧?(但通用)

退出

    std::cout << "Bye!" << std::endl;
    return 0;
}

只需使用迭代器(在适当的情况下使用常量)。

如果你真的对到处传递开始/结束对过敏,请考虑使用 Boost.Range 或类似的东西:它可以让您将[start,end)对捆绑到单个对象中。

如果您不想要副本,请遵循与 std:: 算法库相同的习语,并使用开始和结束迭代器。 迭代器重量轻,不承担复制操作的成本。

在 C++11 中,所有容器都获得了 cbegin()cend() 函数,这允许您从非 const 容器创建const_iterator。之后,只需修改您的算法以接受开始和结束迭代器,您就完成了。

print_range(data.cbegin()+3, data.cend()-3);

如果您坚持使用 C++03,您可以使用轻转发功能将任何对象转换为其const版本:

template<class T>
T const& as_const(T const& v){ return v; }

然后:

print_range(as_const(data).begin()+3, as_const(data).end()-3);

或者是声明所有函数的解决方案,例如 f(const vector::iterator &start, const vector::iterator &en)。

是的。

STL算法就是这样做的,对吧?(但通用)

是的。一般也这样做。标准库算法是一个很好的建模示例。

增强范围将接近您的预期。

下面的示例显示了一个示例

  • 使用切片适配器创建矢量的子范围"视图"(无副本)
  • 显示修改原始(底层)矢量元素会导致该视图中的数据发生更改
  • 使用make_iterator_range来执行大致相同的操作。

请注意,适配器是比简单迭代器范围更灵活的抽象。

#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <vector>
using namespace boost::adaptors;
int main(int argc, const char *argv[])
{
    std::vector<int> v { 0, 1, 2, 3, 4, 5, 6 };
    auto output = std::ostream_iterator<int>(std::cout, ",");
    auto&& slice = v | sliced(2, 5);
    boost::copy(slice, output); 
    std::cout << 'n';
    v[3] += 10;
    boost::copy(slice, output); 
    std::cout << 'n';
    /// Alternative without adaptors:
    auto range = boost::make_iterator_range(v.begin()+3, v.end());
    boost::copy(range, output); 
    std::cout << 'n';
}

在 http://liveworkspace.org/code/5be869c15f534b6161e61c392c181f2d 上观看直播

执行输出:

2,3,4,
2,13,4,
13,4,5,6,