Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: std::vector - It is possible to "slice" a vector?

I am writing some code to integrate ODE's. This question is as much a request for coding advice as for a solution, so if you have an alternative suggestion to the one I am about to offer please let me know!

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

The first 3 doubles are position coordinates; x, y and z. The next 3 doubles are velocity coordinates; x, y and z.

So, now you know that, I have a function which takes pairs of "position" """vectors""" as arguments and returns some sort of result... See where I'm going with this?

Currently the function expects 2 lots of position coordinates in the following manner:

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 in group of 3 to new vectors - that's a crazy (and very slow) way to program something.

I could use pointers to the raw data instead... and just pass a pointer to the x coordinate (first item in a block of 3 doubles) - this seems kind of okay to me but perhaps there's a better method? Kind of something like Python or Matlab array slicing? Can I do something like that?

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

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

Okay so the above is nonsensical, because presumably a language which implemented that syntax would still make a copy operation, which is likely to be slow - exactly what I am trying to avoid...

So yeah I am not sure exactly the best way to proceed here - can anyone suggest a "good" solution? (In the non-subjective way!)

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 - would the compiler optimize my code for me by doing something like changing the function to accept arguments in the following way:

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

In which case, perhaps this question isn't important? (Other than form a "make your code look nice to read" point of view.)

Edit 3: Therefore it is still important.

like image 550
FreelanceConsultant Avatar asked Jun 08 '15 19:06

FreelanceConsultant


People also ask

Can I slice a vector in C++?

CPP. Method 3: We can also use inbuilt function slice() in C++ STL to slice the given vector.

How do you split a vector?

Steps to Split Vectors into ComponentsStep 1: Identify the magnitude of the vector. Step 2: Identify the angle of the vector from the normal. Step 3: Split the vector into the X-component. Step 4: Split the vector into the Y-component.

How do you destroy a vector in C++?

The C++ function std::vector::clear() destroys the vector by removing all elements from the vector and sets size of vector to zero.

How to slice a vector in C++?

Pre-requisite: Vectors in C++ Slicing a vector means to make a subvector from a given vector. Given N integers in a vector arr and to positive numbers X and Y, the task is to slice the given vector from index X to Y in a given vector. Examples: Input: vector arr = { 1, 3, 4, 2, 4, 2, 1 }, X = 2, Y = 5 Output: 4 2 4 2

How to get a sub-vector of a vector in C++?

1. Using Range Constructor The idea is to get input iterators to the starting and ending position in the vector and pass them to the range constructor of the vector class to get a sub-vector. 2. Using std::copy function

What is the use of slice class in C++?

std::slice is the selector class that identifies a subset of std::valarray. An object of type std::slice holds three values: the starting index, the stride, and the total number of values in the subset. Objects of type std::slice can be used as indexes with valarray’s operator[]. class slice; In simple terms it is used to slice based on an index.

How to copy elements from one vector to another vector?

Recommended: Please try your approach on {IDE} first, before moving on to the solution. Method 1: The idea is to copy the elements from this range X to Y to a new vector and return it. Copy the elements in these range between these iterators using copy () function in vector.


2 Answers

You want a view into an existing vector.

std::experimental::array_view<T>, or roll your own.

An array view is a pair of T*, and accessors that let you treat it sort of like an array operator[] .begin() .back() size() empty() etc.

Here is one of many such implementations I've rolled. That one is a bit heavy weight, with a range<Iterator> view that adaptively handles random access iterators, and an array_view<T> that inherits from range<T*>.

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

Once you have it, { vec.data()+index, vec.data()+index+3 } will construct an array_view<double> with next to zero overhead.

like image 194
Yakk - Adam Nevraumont Avatar answered Sep 28 '22 06:09

Yakk - Adam Nevraumont


If what you want is vectors, in the math sense, of 6 elements of type double, std::vector<double> might not be the most efficient representation. I would just go ahead and define a 3D point and then the position + velocity as:

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

Operating on this types will probably be more efficient than operating on vectors (no dynamic allocations), and you could just operate on this as values. A whole copy of this structure is probably cheaper than inserting the first element into the std::vector, and a bit slower but not much than providing two pointers into an array to get a slice.

Additionally it will be less error prone, as in the case of slicing an array you could by mistake use the wrong values and end up with things like (pseudo code) slice[1..3] that is two of the position coordinates with one of the velocity coordinates (probably non-sensical).

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

like image 40
David Rodríguez - dribeas Avatar answered Sep 28 '22 04:09

David Rodríguez - dribeas