Search code examples
c++c++14stdarray

How to split std::array without copying?


I need to access an std::array<double, 9> x by two functions, namely funA and funB. funA only needs the first 6 entries of x and funB the last 3 entries. I am limited to C++14.

I know there are many possibilities to do so, however, I am trying to figure out whether my way is OK in your opinion. Performance has highest priority in my case, and since my code is running in an infinite loop copying is a no go.

What I did is:

// somewhere in the class definition: declare member variables of a class

void funA(const std::array<double, 6> &xA); 
void funB(const std::array<double, 3> &xB); 

std::array<double, 9> x;
std::array<double, 6> xA;
std::array<double, 3> xB;


// somewhere in the loop
std::move(x.begin(), x.begin() + xA.size(), xA.begin());
std::move(x.begin() + xA.size(), x.end(), xB.begin());

funA(xA);
funB(xB);

std::move(xA.begin(), xA.end(), x.begin());
std::move(xB.begin(), xB.end(), x.begin() + xA.size());

So, I though I simply move the corresponding pieces of x into xA and xB, I call funA and funB and finally I stitch x back together from xA and xB in order to keep going with x for the rest of my code. Note: xA and xB are passed as const reference.

Is that a valid way to go? Is there something that could go wrong? Is moving back and forth OK or a no go? Or is this procedure not that fast at all?

So far, in my few testings it seems to work, however, I don't feel safe yet. I didn't get too much in contact with std::move yet, so any comment or hint is very much appreciated.


Solution

  • Moving doubles is a copy. You need to change the parameters of funA and funB to take a view of your array. The easiest would be with the C style double * ptr, size_t size, but you can wrap that in a struct.

    Microsoft's GSL library includes a span type, very similar to std::span, and is compatible with C++14.

    e.g.

    // somewhere in the class definition: declare member variables of a class
    std::array<double, 9> x;
    
    // somewhere in the loop
    funA(gsl::span<double, 9>(x).first<6>());
    funB(gsl::span<double, 9>(x).last<3>());