首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >理解移动语义与模板元编程的好处

理解移动语义与模板元编程的好处
EN

Stack Overflow用户
提问于 2012-05-24 01:54:10
回答 5查看 1.9K关注 0票数 17

我在C++11中读过一些关于移动语义的描述,我想知道它可以在什么上下文中使用。目前,许多C++数学库使用模板元编程来延迟计算。

如果M = A + B + C*D,其中M、A、B、C和D是矩阵,则模板元编程允许避免无用副本。移动语义是一种更方便的方式来做这类事情吗?

如果不是,在什么上下文中使用移动语义。如果是,与这种用途的模板元编程相比,有什么不同/限制?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-05-24 02:19:45

我不是这些优化方面的专家,但据我所知,你所说的延迟求值技术是通过在矩阵类型上定义算术运算符来工作的,例如,A+B+C*D不返回矩阵,它返回一个可以转换为矩阵的代理对象。当它被赋值给M时就会发生这种情况,转换代码将通过库设计人员能想到的最有效的方法来计算结果矩阵的每个单元,从而避免临时矩阵对象。

因此,假设程序包含M = A + B + C * D;

如果你只是用通常的方式使用operator+=实现operator+,那么一旦C++03风格的复制省略生效了,你就会得到类似这样的东西:

代码语言:javascript
运行
复制
Matrix tmp1 = C;
tmp1 *= D;
Matrix tmp2 = A;
tmp2 += B;
tmp2 += tmp1;
M = tmp2;

对于延迟的评估,您可能会得到更多类似的结果:

代码语言:javascript
运行
复制
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;
    }
}

而“没什么聪明”的代码会做几个单独的加法循环和更多的赋值。

据我所知,在这种情况下,移动语义没有多大帮助。在您编写的代码中,没有任何内容允许我们从ABCD迁移,因此我们最终将得到等价物:

代码语言:javascript
运行
复制
Matrix tmp1 = C;
tmp1 *= D;
Matrix tmp2 = A;
tmp2 += B;
tmp2 += std::move(tmp1);
M = std::move(tmp2);

因此,除了最后一点之外,移动语义没有任何帮助,其中可能右值版本的运算符比常规运算符更好。如果您编写了std::move(A) + std::move(B) + std::move(C) * std::move(D),还有更多可用代码,因为我们不必复制CA,但我仍然不认为结果会像延迟求值代码那样好。

基本上,移动语义对延迟求值提供的优化的一些重要部分没有帮助:

1)对于延迟评估,中间结果永远不需要真正作为完整矩阵存在。移动语义不会使编译器在某些时候避免在内存中创建完整的矩阵A+B

2)对于延迟求值,我们可以在计算完整个表达式之前就开始修改M。移动语义对编译器重新排序修改没有帮助:即使编译器足够聪明,能够发现潜在的机会,如果有抛出异常的危险,对非临时性的修改也必须保持正确的顺序,因为如果A + B + C * D的任何部分抛出,那么M必须保持其启动时的顺序。

票数 13
EN

Stack Overflow用户

发布于 2012-05-24 02:12:19

我认为,对于您所说的“模板元编程”,一个更准确的术语是expression templates

如果矩阵动态分配数据,则移动语义可以帮助将表达式期间生成数据从一个对象传输到另一个对象(包括传入/传出),例如:

代码语言:javascript
运行
复制
M = A + B + C*D

另一方面,表达式模板将完全消除时间。

如果您的矩阵没有动态分配数据(例如,如果它们是固定大小的),则移动语义根本不会对您的性能有所帮助。

将表达式模板应用于矩阵库将产生最高的性能。这也是一种非常困难的实现技术。移动语义更容易实现,并且可以在表达式模板之外完成(如果可以传输内存等资源的话)。

总而言之:

移动语义不会消除临时内存,但会在临时内存之间转移动态分配的内存,而不是重新分配内存。

表达式模板消除了时效性。

票数 34
EN

Stack Overflow用户

发布于 2012-05-24 02:02:09

他们是两个不同的野兽。移动语义是关于从将要销毁的值中占用资源。当与诸如大整数(需要动态内存分配)的表达式模板混合时,可以简单地占用这样的内存,而不是复制即将被销毁的东西。

对于本质上不可复制的对象(如fstream),移动语义也很重要,但将其设置为可移动是有意义的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10725299

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档