Take the 2-minute tour ×

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?

#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() {

First I create the vector.

    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

Then I want a subset. But I think this makes a copy.

    // 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

How about this approach?

    // 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 {
        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_; }

        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

Or is the solution to declare all functions like f(const vector::iterator &start, const vector::iterator &en). The STL algorithms do this, right? (but generic)


    std::cout << "Bye!" << std::endl;
    return 0;
share|improve this question
Your SubsetType isn't read-only, because the vector elements can be modified using the iterators. You can fix that by returning const_iterator instead. But you might be better off looking at Boost.Range. –  Steve Jessop Oct 11 '12 at 22:19
llvm::ArrayRef –  Benjamin Lindley Oct 11 '12 at 22:20
boost::range + cbegin/cend. –  Mooing Duck Oct 11 '12 at 22:20
add comment

5 Answers

up vote 2 down vote accepted

Just use iterators (const ones where appropriate).

If you're really allergic to passing begin/end pairs around everywhere, consider using Boost.Range or something similar: it lets you bundle the [start,end) pair into a single object.

share|improve this answer
This looks promising, I'll look into it. –  Daniel Oct 11 '12 at 22:32
add comment

If you don't want a copy follow the same idiom as the std:: algorithms library and utilize a start and end iterator. The iterators are light weight and don't carry the cost of the copy operation.

share|improve this answer
add comment

In C++11, all containers get the cbegin() and cend() functions, which allow you to create const_iterators even from a non-const container. After that, just amend your algorithm to accept a begin and end iterator, and you're done.

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

In case you're stuck with C++03, you can use a light forwarding function that turns any object into its const version:

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

And then:

print_range(as_const(data).begin()+3, as_const(data).end()-3);
share|improve this answer
add comment



The STL algorithms do this, right? (but generic)

Yes. Do it generically as well. The standard library algorithms are a very good example to model.

share|improve this answer
add comment

Boost Range would be close to what you intend.

Below sample shows an example that

  • uses the sliced adaptor to create a subrange 'view' of a vector (without copy)
  • shows that modifying the original (underlying) vector elements, results in changed data in that view
  • Uses make_iterator_range to do roughly the same.

Note that the Adaptors are a far more flexible abstraction than simple iterator ranges.

#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <vector>

using namespace boost::adaptors;


    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';

See it live on http://liveworkspace.org/code/5be869c15f534b6161e61c392c181f2d

Execution output:

share|improve this answer
sliced allows modifications of the range. –  Xeo Oct 11 '12 at 22:23
@Xeo wokay, made it const –  sehe Oct 11 '12 at 22:24
Requires an extra variable, tho, and in that case, he may aswell have done std::vector<int> const& cdata = data; print_range(cdata.begin(), cdata.end()); :/ –  Xeo Oct 11 '12 at 22:25
Well, then I probably don't see what the OP is after. Adding iterator range sample for completeness –  sehe Oct 11 '12 at 22:28
add comment

Your Answer


