Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

reinterpreting array of doubles as array of std::complex<double>

While C++11 standard says this about reinterpreting std::complex<double> as doubles:

For any pointer to an element of an array of complex<T> named p and any valid array index i, reinterpret_cast<T*>(p)[2*i] is the real part of the complex number p[i], and reinterpret_cast<T*>(p)[2*i + 1] is the imaginary part of the complex number p[i]

The intent of this requirement is to preserve binary compatibility between the C++ library complex number types and the C language complex number types (and arrays thereof), which have an identical object representation requirement.

Is it true for the backward reinterpreting? I mean is it safe to perform something like this: std::complex<double> *cppComplexArray = reinterpret_cast<std::complex<double> *>(cDoublesArray) where cDoublesArray have a type of double * and even length 2 * n? What are potential pitfalls if its length will be odd (2 * n + 1)?

like image 227
Drobot Viktor Avatar asked Oct 15 '21 22:10

Drobot Viktor


2 Answers

Is it true for the backward reinterpreting? I mean is it safe to perform something like this: std::complex<double> *cppComplexArray = reinterpret_cast<std::complex<double> *>(cDoublesArray)

Casting/initialization itself is safe, using the result as-if pointing to an element of an array of std::complex<double> is not.

When cDoublesArray (or the array-to-pointer conversion applied to it, if cDoublesArray denotes an array of doubles) points to the first element of an array of doubles, reinterpret_cast<std::complex<double>*>(cDoublesArray) does the same (has the same value).

Using an expression of type std::complex<double>* whose value «pointer to an object of type double» (like reinterpret_cast<std::complex<double>*>(cDoublesArray) or cppComplexArray) in pointer arithmetic (e.g. cppComplexArray + 0) would violate [expr.add]/6:

For addition or subtraction, if the expressions P or Q have type “pointer to cv T”, where T and the array element type are not similar, the behavior is undefined.

(T is std::complex<double>, array element type is double here, and they are not similar)

like image 130
Language Lawyer Avatar answered Oct 11 '22 09:10

Language Lawyer


In practice the backward reinterpreting will probably work most of the time, in view of the strong constraints of the forward reinterpreting impose (see on cppreference, std::complex, implementation notes).

However, I'm not totally sure that such backward reinterpreting would in always work in theory:

  • Let's imagine an absurd and hypothetical implementation of a complex library that would maintain a list of addresses of active complex objects (e.g. for debugging purpose). This (probably static) list would be maintained by the complex constructor and destructor.
  • Every complex operation in this library would verify if its operands are in the list.
  • While forward reinterpreting would work (the complex objects were well constructed and its parts can be used as doubles), the backward reinterpretation would not work (e.g. despite a compatible layout, you would reinterpret as complex a pair of doubles and if you'd perform any complex operation on them, it would fail since the complex was not properly constructed, i.e. its address is not in the list).

As said, this complex library would probably be a stupid idea. But such a library could be implemented and compliant with the standard specs. This is sufficient to prove that there is no reverse guarantee in theory.

The last point of your question is easier and more obvious to answer, supposing we would have an implementation where the reverse reinterpretation works. The missing last column would lead to an access of a part that is out of bounds. This would therfore lead to UB.

Additional readings: This working paper of the standard committee requests a general convertability feature that would generalize the bahavior of reinterpret_cast on complex for other types. It explains the complex case in section 4 and the special handling required from the compiler to make it work if complex is not itself implemented by an array.

like image 26
Christophe Avatar answered Oct 11 '22 09:10

Christophe