Own是否假设别名?
Does Eigen assume aliasing?
Matrix multiplication is the only operation in Eigen that assumes aliasing by default.
MatrixXf mat1(2,2);
mat1 << 1, 2, 4, 7;
MatrixXf mat2 = mat1;
auto result = mat1 * mat2;
Eigen 在临时矩阵中计算乘积 mat1 * mat2
,然后在计算后用于初始化 result
。由于 result
没有出现在右侧,我们不需要别名:
MatrixXf result;
result.noalias() = mat1 * mat2;
现在,乘积mat1 * mat2
直接计算为result
。
到目前为止,还不错。但是在这种情况下会发生什么?
template <typename T1, typename T2>
auto multiplication(const T1& A, const T2& B) // I'm using C++17, decltype not needed
{
return A*B;
}
int main()
{
auto result = multiplication(mat1, mat2); // say mat1 and mat2 are the same as above
// or even this
mat1 = multiplication(mat1, mat2);
return 0;
}
我会说不会出现别名,因为 multiplication(m1,m2)
是一个 rvalue
并且直接在 result
中构造,这要归功于 RVO。我会对行 mat1 = multiplication(mat1, mat2).
说同样的话 我们可以说有一种方法可以将 mat1
与另一个矩阵相乘并将结果存储在同一个矩阵 mat1
中,而无需使用临时变量矩阵(因此,避免混叠)。
问题:
Eigen 假设此处存在别名还是我的假设正确?
您还应该阅读 Common Pitfall 关于使用 auto
关键字的内容。
如果你写
MatrixXf mat1, mat2;
auto result = mat1 * mat2;
或
template <typename T1, typename T2>
auto multiplication(const T1& A, const T2& B) { return A*B; }
那么 auto
的类型实际上就是 Product<MatrixXf, MatrixXf>
或 Product<T1,T2>
的类型,也就是说,此时根本没有计算发生。
因此
MatrixXf mat1 = MatrixXf::Random(2,2), mat2 = MatrixXf::Random(2,2);
auto result = multiplication(mat1, mat2); // no computation happens here
// this is safe (Eigen assumes aliasing can happen):
mat1 = result; // equivalent to directly assign mat1 = mat1 * mat2;
// Pitfall: "result" now refers to a modified `mat1` object!
// this will give undefined results (you may need bigger matrices to actually see this):
mat1.noalias() = mat1*mat2; // tell Eigen this does not alias, but actually it does.
附录:在评论中指出了赋值和初始化之间的区别。事实上,在初始化期间,Eigen 假设没有发生别名,例如,以下直接分配给结果(没有临时对象):
MatrixXf result = mat1 * mat2; // initialization, not assignment!
附录2:如果你写了(假设foo
的return类型是Object
):
Object A;
A = foo(A);
一定有某种隐式赋值发生(C++11 可能是移动赋值,如果 Object
允许的话)。这不同于
Object A;
Object B = foo(A); // RVO possible (depending on foo).
Matrix multiplication is the only operation in Eigen that assumes aliasing by default.
MatrixXf mat1(2,2);
mat1 << 1, 2, 4, 7;
MatrixXf mat2 = mat1;
auto result = mat1 * mat2;
Eigen 在临时矩阵中计算乘积 mat1 * mat2
,然后在计算后用于初始化 result
。由于 result
没有出现在右侧,我们不需要别名:
MatrixXf result;
result.noalias() = mat1 * mat2;
现在,乘积mat1 * mat2
直接计算为result
。
到目前为止,还不错。但是在这种情况下会发生什么?
template <typename T1, typename T2>
auto multiplication(const T1& A, const T2& B) // I'm using C++17, decltype not needed
{
return A*B;
}
int main()
{
auto result = multiplication(mat1, mat2); // say mat1 and mat2 are the same as above
// or even this
mat1 = multiplication(mat1, mat2);
return 0;
}
我会说不会出现别名,因为 multiplication(m1,m2)
是一个 rvalue
并且直接在 result
中构造,这要归功于 RVO。我会对行 mat1 = multiplication(mat1, mat2).
说同样的话 我们可以说有一种方法可以将 mat1
与另一个矩阵相乘并将结果存储在同一个矩阵 mat1
中,而无需使用临时变量矩阵(因此,避免混叠)。
问题:
Eigen 假设此处存在别名还是我的假设正确?
您还应该阅读 Common Pitfall 关于使用 auto
关键字的内容。
如果你写
MatrixXf mat1, mat2;
auto result = mat1 * mat2;
或
template <typename T1, typename T2>
auto multiplication(const T1& A, const T2& B) { return A*B; }
那么 auto
的类型实际上就是 Product<MatrixXf, MatrixXf>
或 Product<T1,T2>
的类型,也就是说,此时根本没有计算发生。
因此
MatrixXf mat1 = MatrixXf::Random(2,2), mat2 = MatrixXf::Random(2,2);
auto result = multiplication(mat1, mat2); // no computation happens here
// this is safe (Eigen assumes aliasing can happen):
mat1 = result; // equivalent to directly assign mat1 = mat1 * mat2;
// Pitfall: "result" now refers to a modified `mat1` object!
// this will give undefined results (you may need bigger matrices to actually see this):
mat1.noalias() = mat1*mat2; // tell Eigen this does not alias, but actually it does.
附录:在评论中指出了赋值和初始化之间的区别。事实上,在初始化期间,Eigen 假设没有发生别名,例如,以下直接分配给结果(没有临时对象):
MatrixXf result = mat1 * mat2; // initialization, not assignment!
附录2:如果你写了(假设foo
的return类型是Object
):
Object A;
A = foo(A);
一定有某种隐式赋值发生(C++11 可能是移动赋值,如果 Object
允许的话)。这不同于
Object A;
Object B = foo(A); // RVO possible (depending on foo).