Question

Does the following code violate strict aliasing or otherwise result in undefined behaviour according to the C++11 standard? Are there better ways to achieve the same functionality?

void do_things(const std::array<char, 64> &block) {
   // ...
}

int main() {
    std::vector<char> buffer(64);
    do_things(reinterpret_cast<const std::array<char, 64> &>(buffer[0]));
}

tldr: Using const char * is a lot less painful

edit: since sizeof(std::array<char, n>) isn't guaranteed to be equal to n, I then propose the following:

void do_things(const char (&block)[64]) {
   // ...
}

int main() {
    std::vector<char> buffer(64);
    do_things(reinterpret_cast<char (&)[64]>(buffer[0]));
}

According my understanding of aliasing this should not result in undefined behaviour and capture the semantics of passing an array of fixed size. Is my understanding correct?

Was it helpful?

Solution

The strict aliasing rule refers to §3.10 [basic.lval]/p10, which provides that

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:

  • the dynamic type of the object,
  • a cv-qualified version of the dynamic type of the object,
  • a type similar (as defined in 4.4) to the dynamic type of the object,
  • a type that is the signed or unsigned type corresponding to the dynamic type of the object,
  • a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,
  • an aggregate or union type that includes one of the aforementioned types among its elements or nonstatic data members (including, recursively, an element or non-static data member of a subaggregate or contained union)
  • [...]

Thus, accessing an object of type char through a glvalue of type std::array<char, N> does not break this rule, because std::array<char, N> is an aggregate type that includes char as an element of a nonstatic subaggregate data member.

However, you still can't do anything useful with the resulting reference without invoking undefined behavior because of a different rule - §9.3.1 [class.mfct.non-static]/p2:

If a non-static member function of a class X is called for an object that is not of type X, or of a type derived from X, the behavior is undefined.

It's also worth noting that no rule in the standard guarantees that sizeof(std::array<T, N>) == sizeof(T) * N. The only things the standard guarantees is that std::array<T, N> is an aggregate type and it can be initialized using a braced-init-list containing up to N Ts. The implementation is free to add extra stuff.

Depending on what do_things needs, you may want to make your function take random access iterators, or simply a pointer. Alternatively, if you want to limit your function to take only std::vector and std::arrays, you can write overloads that take const refs to those and call a helper function taking const char * that does the actual work.


The new version doesn't break any rule I can think of, but it's fairly bad design to require reinterpret_cast to be used pretty much every time your function is called. If you accidentally declared buffer as a std::vector<std::string>, or wrote buffer instead of buffer[0], the compiler will happily compile your code without a warning, with potentially disastrous results.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top