0

We have a large code base mainly written in C. We do a lot of numerical linear algebra.

In C we use double*, with length 3 to model a 3d vector.

In C++ we use std:array<double,3> to model a 3d vector.

We have a small template library to overload a lot of operators, such as

template <class T, size_t N>
std::array<T, N> operator+(const std::array<T, N> &array1, const std::array<T, N> &array2) {
    std::array<T, N> a;
    for (size_t i = 0; i < N; i++) {
        a[i] = array1[i] + array2[i];
    }
    return a;
}

The problem comes, when we need to go from C to C++ (the other way around is no problem, since we can use the .data() method to access the aligned memory). I do not like to make a copy of each c-like 3d vector, because this would be numerically expensive.

Can I treat a pod array as a std::array or is there a way of initializing an std::array in a way that no new memory is allocated, but the memory from the pod array is used?

I am thinking about using gsl::span from the guideline support library, but I wonder if there is a better solution.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
schorsch312
  • 5,553
  • 5
  • 28
  • 57
  • Is the C variant an array (`double[3]`) or dynamically allocated (`malloc(3*sizeof(double)`)? You might want to take a look at [`array_view`](https://msdn.microsoft.com/en-us/library/hh305260.aspx) in the first case. – Henri Menke Feb 16 '18 at 09:33

1 Answers1

-2

You can simply cast:

double* c_array; // assign to whatever you like, length 3 or more
auto cpp_array = reinterpret_cast<std:array<double,3>*>(c_array);

This works because std::array is definitely nothing more than a struct containing a single C array.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • 1
    I agree that this will work with every sensible implementation of the standard library, but there is nothing in the standard that guarantees it, right? Some implementation of `std::array` could perhaps add some additional debugging fields before the actual array... – michalsrb Feb 16 '18 at 09:39
  • 1
    I suspect it's Undefined Behavior. Yes, a `std::array` **contains** a `T[N]`. That doesn't mean it _is_ a `T[N]`. And accessing an object via an expresion of incompatible type is UB. – MSalters Feb 16 '18 at 09:39
  • [No, it is not safe even if `std::array` is nothing more than a struct containing a single C array.](https://stackoverflow.com/questions/48444004/is-it-undefined-behavior-to-reinterpret-cast-a-t-to-tn) – xskxzr Feb 16 '18 at 09:47
  • @michalsrb: No, std::array cannot contain additional debugging fields. Not only is there nothing sensible to debug by doing so, but the widespread use of std::array in a way that demands it is a simple array internally would never allow such an implementation to succeed (meaning, have users). – John Zwinck Feb 16 '18 at 10:19
  • @JohnZwinck: I can imagine things you could debug on `std::array`. For example a debug version of standard library could add a canary field before and after the array contained in `std::array` and test them in every method to detect out-of-bounds writes. That is plausible thing to do. It wouldn't break valid programs, but will break programs with this `reinterpret_cast`. – michalsrb Feb 16 '18 at 11:37
  • @michalsrb: It will break "valid" programs because people use std::array as a member of network messages and other things. In practice what you are proposing is completing implausible because of how people use arrays (C and C++ ones). – John Zwinck Feb 16 '18 at 11:39