Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sub-vector modifies original vector

Tags:

c++

stl

vector

I want to extract a sub-vector. Then modify its elements which affects the original vector. My sample code below:

#include <vector>
#include <iostream>

using namespace std;

void printvec(vector<int>& v){
        for(int i = 0;i < v.size();i++) {cout << v[i] << " ";}
        cout << endl;
}

int main(){
        vector<int> original;
        for(int i = 1;i <= 10;i++) original.push_back(i);
        printvec(original);

        vector<int> subvector(original.begin()+4, original.end()-2);
        subvector[0]=0;
        subvector[1]=0;
        printvec(subvector);
        printvec(original);
        return 0;
}

In above code, subvector does not modify vector. Can some one point me to an elegant way to make a subvector which modifies original vector (hopefully without explicit use of pointers if possible).

like image 938
beginner 101 Avatar asked Jul 19 '26 19:07

beginner 101


2 Answers

If you don't want to use a pointer, you could create a slice class to forward the work to - which will just be a pair of iterators and whatever other operations you might need:

template <typename T>
class slice {
    using iterator = typename T::iterator;
    using reference = typename std::iterator_traits<iterator>::reference;

    slice(iterator first, iterator last)
        : first(first), last(last)
    { } 

    reference operator[](size_t idx)
    {   
        return *std::next(first, idx);
    } 

    iterator begin() const { return first; }  
    iterator end() const { return last; }

private:
    iterator first, last;
};

With that, you can do your slicing thusly:

    slice<vector<int>> subvector(original.begin()+4, original.end()-2);
    subvector[0]=0; // changes original[4]
    subvector[1]=0; // changes original[5]

If you change your printvec to take an arbitrary container and use a range-for to iterate over it, you can print the subvector too. It will contain:

0 0 7 8 
like image 179
Barry Avatar answered Jul 21 '26 09:07

Barry


The line:

vector<int> subvector(original.begin()+4, original.end()-2);

creates a new vector and copies the elements from original.begin()+4 to original.end()-2 to the new one. Even with pointers, there is no way I would call elegant to achieve what you want, because many change to the original vector (rezise / push_back) could potentially invalidate the pointers to its elements.

Depending on the exact functionality you want to implement, you can use a class like this:

#include <vector>
#include <iostream>

using namespace std;

template<class T>
class Subvector {
    std::vector<T>*const  vec;
    size_t start;
    size_t end;
public:
    Subvector(std::vector<T>& vector, size_t start, size_t end) :
        vec(&vector),
        start(start),
        end(end)
    {}
    size_t size() const { return end - start; }
    T& operator[](size_t i) {
        return (*vec)[start + i];
    }
    const T& operator[](size_t i) const {
        return (*vec)[start + i];
    }
};

template<class VEC>
void printvec(const VEC& v){
    for (int i = 0; i < v.size(); i++) { cout << v[i] << " "; }
    cout << endl;
}

int main(){
    vector<int> original;
    for (int i = 1; i <= 10; i++) original.push_back(i);
    printvec(original);

    Subvector<int> subvector(original,4, original.size() - 2);
    subvector[0] = 0;
    subvector[1] = 0;
    printvec(subvector);
    printvec(original);
    return 0;
}
like image 39
MikeMB Avatar answered Jul 21 '26 10:07

MikeMB