Is it possible to send part of vector as a vector

2019-05-07 16:34发布

问题:

This question already has an answer here:

  • Can we send part of vector as a function argument? 5 answers

I want to see if it is possible to pass part of vector to a function so that it appears as a normal vector to the function. More importantly, I want this to be done in O(1), constant time. I don't want to iterate the vector to make a new one. In fact, I also want the size of the new vector to change to 40 in the following example.

void func(vector <int> &v){

    //calling index 10  to 50 of v
    func(v[10..50])
}

回答1:

Use iterators as the parameters to the range-based function, and pass in the required range. Your code in the function become

funcWithRange(v.cbegin()+10, v.cbegin()+50);

with function signature

void funcWithRange(std::vector<int>::const_iterator first, std::vector<int>::const_iterator last)

This could be generalized by making this a function template with the vector member type as its template parameter, or still further to any container supporting this type of range iteration. As noted in the comments, <algorithm> has many examples of this pattern.

std::distance(first, last); will return the desired altered size. I don't think you can get closer to meeting your requirements without making a physical copy.



回答2:

There is a means to achieve something similar to this that is being proposed for inclusion in the C++ standard. It is called a span and it operates like a vector in some ways.

#include <gsl/span>

void func(gsl::span<int> sp)
{
    for(auto& i: sp)
        std::cout << i << '\n';
}

int main()
{
    // ...

    std::vector<int> v(100);

    // put something in the vector (numbers 0 - 99)
    std::iota(std::begin(v), std::end(v), 0);

    // wrap the container in a span
    auto sp = gsl::make_span(v);

    // send parts of it to functions
    func(sp.subspan(10, 50));
}

The span presents a window onto the original vector so it is a reference type. It doesn't contain its own data just pointers to the data in the vector. As such they are lightweight and designed to be passed by value.

An implementation of span can be found here: https://github.com/Microsoft/GSL

This is the recommended way of passing contiguous containers in the Best Practices guide by Bjarne Stroustrup and Herb Sutter.

The guidelines can be found here: CppCoreGuidelines.md



回答3:

If you have a vector of say 100 elements

std::vector<int> v(100);

and you want to call void f(std::vector<int> v) with the first 10 elements, simply call the function as

f({v.cbegin(), v.cbegin() + 10});

That will construct a new vector from the two iterators (by copying the elements) and pass the new vector to f.