我对这些优化没有专家,但据我了解,通过定义矩阵类型上的算术操作员,您谈论的延迟评价技术是工作,例如,A+B+C*D
不返回矩阵,它返回一个可以将 转换为矩阵的代理对象。当它被指定到 M
时,就会发生这种情况,转换代码将以最有效的方式计算结果矩阵中的每个单元格,即图书馆设计师可以生成,避免临时矩阵对象。
所以,假设程序包含 M = A + B + C * D;
如果您除了用通常的方式执行 operator@/code> 来执行
operator@/code>之外, 没有其他聪明的动作, 您就会得到类似的东西, 通常情况下, C+/ 03 式的复制除去被踢入 :
Matrix tmp1 = C;
tmp1 *= D;
Matrix tmp2 = A;
tmp2 += B;
tmp2 += tmp1;
M = tmp2;
随着评估的延迟,你可能会得到更像:
for (int i = 0; i < M.rows; ++i) {
for (int j = 0; j < M.cols; ++j) {
/* not necessarily the best matrix multiplication, but serves to illustrate */
c_times_d = 0;
for (int k = 0; k < C.cols; ++k) {
c_times_d += C[i][k] * D[k][j];
}
M[i][j] = A[i][j] + B[i][j] + c_times_d;
}
}
而"一无所知"的代码 会做一些不同的 额外的循环 和更多的任务。
据我所知,在此情况下,移动语义没有多大帮助。 您写入的文字中没有任何内容允许我们从 A
, B
, C
或 D
移动,所以我们最后将使用以下等同的方法:
Matrix tmp1 = C;
tmp1 *= D;
Matrix tmp2 = A;
tmp2 += B;
tmp2 += std::move(tmp1);
M = std::move(tmp2);
移动语义除上一个位数外没有帮助, 在那里操作员的 rvalu 版本可能比普通操作员更好。 如果您写入 < code> std:: move( A) + std:: move( B) + std:: move( C) * std:: move( D) code >, 因为我们不需要复制 < code> C code > 或 < code> A < /code >, 但我仍然认为结果不如延迟评价代码好。
移动语义对于延迟评价所提供的优化的某些重要部分毫无帮助:
1)由于评价延迟,中间结果从不需要以完整的矩阵形式实际存在。移动语义无法避免编译者在某个时刻创建完整的内存矩阵 < code> A+B 。
2) 延迟评价后,我们可以在完成整个表达式计算之前开始修改 M
。移动语义不会帮助编译者重新排序修改:即使汇编者足够聪明,能够发现潜在的机会,但如果存在任何被抛出例外的危险,则非时空 < em> mustt 的修改应保持正确的顺序,因为如果 A+B+C* D < /code> 投出,那么
M < /code> 的任何部分必须保留在启动时。