Is this undefined behavior?
std::array<int, 5> x = {3, 5, 1, 2, 3};
std::array<int, 3>& y = *reinterpret_cast<std::array<int, 3>*>(&x[1]);
for(int i = 0; i != 3; i++) {
std::cout << y[i] << "\n";
}
Maybe yes, but I really feel like there should be a safe way to slice std::array
s.
EDIT: Following Radek's suggestion:
template<unsigned N, unsigned start, unsigned end, typename T>
std::array<T, end - start>& array_slice(std::array<T, N>& x)
{
static_assert(start <= end, "start <= end");
static_assert(end <= N-1, "end <= N");
return *reinterpret_cast<std::array<T, end - start>*>(&x[start]);
}
EDIT: Ok, I decided that I'm unhappy with std::array
s and will move to something else, any ideas?
What about a placement new?
#include <array>
#include <iostream>
#include <iterator>
template<typename T, std::size_t N>
struct array_slice : public std::array<T,N> {
~array_slice() = delete;
};
int main() {
std::array<double,4> x_mu{0.,3.14,-1.,1.};
std:: cout << &x_mu << std::endl;
{
auto slicer = [] (std::array<double,4>& ref) {
array_slice<double,3>* p = new (&ref) array_slice<double,3>;
return p;
};
std::array<double,3>& x_ = *slicer(x_mu);
std::copy(x_.begin(),x_.end(),
std::ostream_iterator<float>(std::cout," "));
std:: cout << std::endl;
std:: cout << &x_ << std::endl;
}
std::copy(x_mu.begin(),x_mu.end(),
std::ostream_iterator<float>(std::cout," "));
}
Yes, that is undefined behavior. You're taking one type and reinterpret_cast
ing it to another. Indeed, the use of the reinterpret_cast
should be a big red flag for "here there be dragons!"
As for slicing arrays, that's not going to happen. A std::array
contains values; a slice of this would contain references to part of that array. And therefore, it would not be a std::array
. You can copy slices of arrays, but not using std::array
. You would need to use std::vector
, since it allows the calling of constructors, as well as construction from a range of values. Remember: std::array
is just a nicer wrapper around a C-style array.
The committee is looking into a template array_ref<T>
class, which is exactly what it says: a reference to some segment of an array of type T
. This could be a regular C-style array, a std::vector
, a std::array
, or just some memory allocated with new T[]
. There are some library implementations of the class already, but nothing is standardized yet.
Following Radek's suggestion:
Hiding the undefined behavior in a function does not make it defined behavior. You can try to pretend that it isn't undefined, but it still is. The moment you use that reinterpret_cast
, you willingly give up living in C++-land.