Domanda

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?

È stato utile?

Soluzione

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top