Yes, its an Undefined Behavior, a classic one...
First, understand that what you just did:
std::array<T,n>* ay = (std::array<T,n>*) ptr
can be translated as:
using Arr = std::array<T,n>;
std::array<T,n>* ay = reinterpret_cast<Arr*>( const_cast<TypeOfPtr>(ptr));
You've not just casted away all, const
and volatile
qualification but also casted the type. See this answer: https://mcmap.net/q/41091/-why-use-static_cast-lt-t-gt-x-instead-of-t-x ...indiscriminately casting away cv
qualifications can also lead to UB.
Secondly, It is undefined behavior to access an object through a pointer that was casted from an unrelated type. See the strict aliasing rule (Thanks zenith). Therefore any read or write access through the pointer ay
is undefined. If you are extremely lucky, the code should crash instantly. If it works, evil days are awaiting you....
Note that std::array
is not and will never be the same as anything that isn't std::array
.
Just to add... In the working draft of the C++ standard, it lists out explicit conversion rules. (you can read them) and has a clause stating that
.....
5.4.3: Any type conversion not mentioned below and not explicitly defined by
the user ([class.conv]) is ill-formed.
.....
I suggest you cook up your own array_view
(hopefully coming in C++17). Its really easy. Or, if you want some ownership, you can cook up a simple one like this:
template<typename T>
class OwnedArray{
T* data_ = nullptr;
std::size_t sz = 0;
OwnedArray(T* ptr, std::size_t len) : data_(ptr), sz(len) {}
public:
static OwnedArray own_from(T* ptr, std::size_t len)
{ return OwnedArray(ptr, len); }
OwnedArray(){}
OwnedArray(OwnedArray&& o)
{ data_ = o.data_; sz = o.sz; o.data_=nullptr; o.sz=0; }
OwnedArray& operator = (OwnedArray&& o)
{ delete[] data_; data_ = o.data_; sz = o.sz; o.data_=nullptr; o.sz=0; }
OwnedArray(const OwnedArray& o) = delete;
OwnedArray& operator = (const OwnedArray& o) = delete;
~OwnedArray(){ delete[] data_; }
std::size_t size() const { return sz; }
T* data() return { data_; }
T& operator[] (std::size_t idx) { return data_[idx]; }
};
...and you can roll out more member functions/const qualifications as you like. But this has caveats... The pointer must have been allocated the through new T[len]
Thus you can use it in your example like this:
auto ay = OwnedArray<decltype(*ptr)>::own_from(ptr, ptr_len);