C ++: std :: vector - Can a vector be "sliced"?

I am writing code for ODE integration. This question is as much a coding request as a solution, so if you have an alternative suggestion to the one I'm about to propose, let me know!

The "objects" to be integrated by the ODE integrator are in "blocks" of 6 ... The reason for this is that I have std :: vector doubles and they are arranged like this:

The first 3 double the position coordinates; x, y and z. The next 3 doublings are velocity coordinates; x, y and z.

So now you know that I have a function that takes "position" "" vector "" "pairs as arguments and returns some kind of result ... See where am I going with this?

The function is currently expecting 2 lots of position coordinates as follows:

std::vector<double> magic_gravity_formula(const std::vector<double> &r1,
          const std::vector<double> &r2, const double m1, const double m2)

      

I don't want to copy all the data from group 3 into new vectors - this is a crazy (and very slow) way of programming anything.

Instead, I could use pointers to the raw data ... and just pass a pointer to the x coordinate (the first element in a 3-pair block) - that sounds like me, but maybe there is a better way? Something like slicing a Python or Matlab array? Can I do something like this?

I kind of want to pass in a new vector (or some kind of wrapper class?) Created from the data already stored in the array ... Something like

std::vector<double> sub_section_of_data = data[0..2] // Obviously pseudocode!

      

Ok, so the above is pointless, because presumably the language that implemented this syntax will still do a copy operation, which is likely to be slow - exactly what I'm trying to avoid ...

So yeah, I'm not sure what is the best way to move around here - can anyone suggest a "good" solution? (Not subjective!)

EDIT: To make this really clear - the problem is, I don't want to do something like:

std::vector<double> r1_temp;
r1_temp.push_back(data[0]); // Copy ! Bad !
r1_temp.push_back(data[1]);
r1_temp.push_back(data[2]);

... same for an r2 ...

std::vector<double> force = magic_gravity_formula(r1, r2, m1, m2);

      

EDIT 2: Consider compiler options - will the compiler optimize my code for me by doing something like changing the function to accept arguments like this:

std::vector<double> super_gravity_formula(double x1, double y1, double z1, double x2, double y2, double z2, double m1, double m2)

      

In that case, perhaps this question is not important? (Apart from the "make your code nice to read" form.)

Edit 3: so this is still important.

+3


source to share


4 answers


You want to see an existing vector.

std::experimental::array_view<T>

, or roll your own.

An array view is a pair of T*

and accessors that allow it to be treated like an array operator[]

.begin()

.back()

size()

empty()

, etc.



Here is one of many such implementations that I have deployed . It's a bit heavy weight with a view range<Iterator>

that handles random access iterators adaptively and array_view<T>

that inherits from range<T*>

.

If that doesn't work, search for another post on SO with the word "yakk" with the word "array_view" or debug it yourself. I've written this at least half a dozen times, with more or less debugging, with different rules of correctness const

.

After that, it will { vec.data()+index, vec.data()+index+3 }

build array_view<double>

with zero overhead.

+5


source


If you need vectors, mathematically 6 doubles std::vector<double>

may not be the most efficient representation. I would just go ahead and define a 3D point and then position + speed as:

struct point {
   double x, y, z;
};
struct position_and_velocity {
   point pos;
   point vel;
};

      

Working on these types would probably be more efficient than working on vectors (no dynamic allocations), and you could just use that as values. A whole copy of this structure is probably cheaper than inserting the first element into std::vector

, and a little slower, but not much, than providing two pointers to the array to get the chunk.



Also, it will be less error prone, as in the case of slicing an array, you could mistakenly use the wrong values ​​and end up using things like (pseudo-code) slice[1..3]

which are two of the position coordinates with one of the velocity coordinates (probably insensitive ).

The function signature is part of the binary interface of your program, the compiler will not change the function signature unless it inserts the code. Moreover, I would very much doubt that the compiler will remove the dynamic allocation inherent in vectors in any of the transformations (unless it can remove the entire variable).

+1


source


Since the code is demanding const std::vector<double> &

, you can't be any smarter.

Otherwise (if the library functions were more general) you could easily traverse the range (see Boost Range for example, but you could easily parse a vector subrange like boost::string_ref

or std::string_view

)

0


source


'Instead, I could use pointers to raw data ... and just pass a pointer to the x coordinate.

You yourself answered your own question. std :: algorithms do nothing, otherwise.

0


source







All Articles