Basically you can only create expression/reference of an existing object. When the object is out of scope, the expression/reference is invalid/undefined.
With auto w
, you are creating an expression of a temp Arr2
object, whose life ends after this line , making w
invalid. The assertion you saw helps check this situation. This temp object is created when you cast a Map
object to an Arr2
object at the line of return
, which involves an undesired data copy from the input vector to the temp Arr2
object. This happens to be one of the situations that you should not use auto
. If you would accept one more copy, the following code will work. It is equivalent to you adding .eval()
in your original code.
#include <Eigen/Eigen>
#include <iostream>
using namespace Eigen;
template<typename T>
using Arr = Array<T, Dynamic, 1>;
template<typename T>
using Arr2 = Array<T, Dynamic, Dynamic>;
template<typename T>
Arr2<typename T::Scalar> reshape(const ArrayBase<T> & A, const uint n,
const uint m) {
return Map<const Arr2<typename T::Scalar>>(A.eval().data(), n, m);
}
int main() {
Arr<double> v = Arr<double>::LinSpaced(16, 0, 15);
Arr2<double> w = reshape(v, 4, 4).transpose();
std::cout << w << std::endl;
return 0;
}
Alternatively, changing the return type to Map<const Arr2<typename T::Scalar>>
is a better way to avoid the two copies mentioned above, and you can still use auto
to keep w
as an expression. The following code is a better working version.
#include <Eigen/Eigen>
#include <iostream>
using namespace Eigen;
template<typename T>
using Arr = Array<T, Dynamic, 1>;
template<typename T>
using Arr2 = Array<T, Dynamic, Dynamic>;
template<typename T>
Map<const Arr2<typename T::Scalar>> reshape(const ArrayBase<T> & A,
const uint n, const uint m) {
return Map<const Arr2<typename T::Scalar>>(A.eval().data(), n, m);
}
int main() {
Arr<double> v = Arr<double>::LinSpaced(16, 0, 15);
auto w = reshape(v, 4, 4).transpose();
std::cout << w << std::endl;
return 0;
}
On the other hand, I think your reshape
is still wrong when A is an expression, as A.eval().data()
is a temp object whose life ends after the function call. Your reshape
API will confuse people who don't know this restriction.
Actually creating a reshape function is unnecessary, as constructing a Map
object itself semantically means reshaping some data in a contiguous memory space. I would recommend the following form. It is only a little bit longer than the word "reshape", no temp buffer/data copy involved, and auto w
is still an expression object.
#include <Eigen/Eigen>
#include <iostream>
using namespace Eigen;
template<typename T>
using Arr = Array<T, Dynamic, 1>;
template<typename T>
using Arr2 = Array<T, Dynamic, Dynamic>;
int main() {
Arr<double> v = Arr<double>::LinSpaced(16, 0, 15);
auto w = Map<Arr2<double>>(v.data(), 4, 4).transpose();
std::cout << w << std::endl;
return 0;
}