我有以下代码:
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);
}
Arr<double> v = Arr<double>::LinSpaced(16, 0, 15);
auto w = reshape(v, 4, 4).transpose();
std::cout << w << std::endl;
产生错误
static void Eigen :: internal :: checkTransposeAliasing_impl :: run(const Derived&amp;,const OtherDerived&amp;)[with Derived = Eigen :: Array; OtherDerived = Eigen :: Transpose&gt ;; bool MightHaveTransposeAliasing = true]:断言 `(!check_transpose_aliasing_run_time_selector :: IsTransposed,OtherDerived&gt; :: run(extract_data(dst),other))&amp;&amp; &#34;期间检测到别名 换位,使用transposeInPlace()&#34; &#34;或将rhs评估为a 暂时使用.eval()&#34;&#39;失败。
添加eval
确实解决了问题:
auto w = reshape(v, 4, 4).transpose().eval();
(但添加它作为<< w.eval() <<
的打印行不会。
我希望更好地了解正在发生的事情,并找出是否有另一种解决方法。
谢谢
答案 0 :(得分:0)
基本上,您只能创建现有对象的表达式/引用。当对象超出范围时,表达式/引用无效/未定义。
使用np.trapz()
,您将创建一个临时auto w
对象的表达式,其生命在此行之后结束,使Arr2
无效。您看到的断言有助于检查这种情况。将w
对象转换为Map
行的Arr2
对象时会创建此临时对象,该对象涉及从输入向量到临时{{1}的不需要的数据副本对象。这恰好是the situations that you should not use auto
之一。如果您再接受一个副本,则以下代码将起作用。这相当于您在原始代码中添加return
。
Arr2
或者,将返回类型更改为.eval()
是避免上述两个副本的更好方法,您仍然可以使用#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;
}
将Map<const Arr2<typename T::Scalar>>
保留为表达式。以下代码是更好的工作版本。
auto
另一方面,我认为当A是表达式时,w
仍然是错误的,因为#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;
}
是一个临时对象,其生命在函数调用之后结束。您的reshape
API会让那些不了解此限制的人感到困惑。
实际上创建一个重塑函数是不必要的,因为构造一个A.eval().data()
对象本身在语义上意味着在一个连续的内存空间中重塑一些数据。我会推荐以下表格。它只比“reshape”这个词长一点,没有涉及临时缓冲区/数据拷贝,reshape
仍然是一个表达式对象。
Map