在添加时使用c ++模板如何避免临时对象?

时间:2014-12-09 23:32:28

标签: c++ templates temporary-objects

我正在读Tomas Arce的article。 本文讨论了使用模板提高矢量添加性能的方法。但有些部分我无法遵循。

作者说以下代码可以避免在评估时生成临时对象 vA = vB + vC + vD,但是怎么样?我没有得到如何避免临时对象。是否有人可以解释内部机制,即在使用模板时如何避免临时对象。

template< class ta_a >
class vecarg
{
const ta_a& Argv;
public:
inline vecarg( const ta_a& A ) : Argv( A ) {}
inline const float Evaluate( const int i ) const 
{ return Argv.Evaluate( i ); }
};


template<> 
class vecarg< const float >
{
  const ta_a& Argv;
  public:
  inline vecarg( const ta_a& A ) : Argv( A ) {}
  inline const float Evaluate( const int i ) const { return Argv; }
};


template<> 
class vecarg< const int >
{
  const ta_a& Argv;
  public:
  inline vecarg( const ta_a& A ) : Argv( A ) {}
  inline const float Evaluate( const int i ) const { return (float)Argv; }
};


template< class ta_a, class ta_b, class ta_eval >
class vecexp_2
{
  const vecarg<ta_a>   Arg1;
  const vecarg<ta_b>   Arg2;


  public:
  inline vecexp_2( const ta_a& A1, const ta_b& A2 )
 : Arg1( A1 ), Arg2( A2 ) {}
  inline const float Evaluate ( const int I ) const
  { return ta_eval::Evaluate( i, Arg1, Arg2 ); }
 };

 // Listing 5

P.S。在@Severin Pappadeux提供的第二个链接中,解释很容易理解。基本上,所有表达式模板都是这样的:通过重载运算符+它甚至不执行添加,而是创建一个轻量级对象,其主要工作是对运算符每一侧的两个操作数进行两次引用{ {1}},并且在评估运算符+时完成添加。通过重载操作符=第二次(因为左侧是轻量级对象,右侧是+),对轻量级对象的引用(包含两个先前对{{1}的引用可以创建}和vD)和vB,并在评估运算符vC时再次添加。

3 个答案:

答案 0 :(得分:2)

拿一块像底特律那样大小的盐。它已有14年历史,从那时起,优化器已经大大改善。简而言之,这个家伙正在使用模板制作一个复杂的方法网络,从而转换A = B + C + D:

    // Taking liberties with pseudocode and notation for clarity. This is
    // a very rough oversimplification
    // Create a new, wasteful, vector to store a temporary result
    vector tmp(C.x + D.x, C.y + D.y, C.z + D.z)
    // Create another new, wasteful, vector to store a temporary result:
    vector tmp2(B.x + tmp.x, B.y + tmp.y, B.z + tmp.z)
    // Waste even more time copying the result.
    A.x = tmp2.x; A.y = tmp2.y; A.z = tmp2.z;
    // In reality, your optimized compiler isn't even remotely this stupid.

他正在使用模板预处理器来消除临时和最终副本的创建。他正试图达到执行这样的目的:

    A.x = B.x + (C.x + D.x);
    A.y = B.y + (C.y + D.y);
    A.z = B.z + (C.z + D.z);

请记住,如果你把这样的东西放在其他工程师必须阅读的生产代码中,你就会有更好的理由。就像在,你将必须证明使用这种乱码可以产生关键任务的性能提升。为什么?因为维持这种精神错乱的代价是不可忽视的。在使用此类内容之前,请先获取性能数据。

答案 1 :(得分:0)

技术被称为“表达模板”,其发明者Todd Veldhuizen有几篇论文, 从

开始

http://ubietylab.net/ubigraph/content/Papers/pdf/ExpressionTemplates.pdf

http://www.drdobbs.com/cpp/expression-templates/184401656

最后是托德报告

http://www.cs.indiana.edu/pub/techreports/TR542.pdf

答案 2 :(得分:0)

整个概念依赖于存储对本机类型的引用,或者评估折叠为本机类型的表达式。

有一些临时对象参与其中,但它们存储的所有内容都是对源和目标数据的引用,这些数据会在某些时候得到解决。在没有优化的情况下进行编译可能确实会分配空间,但如果启用了优化,优化器会注意到没有理由这样做。

也就是说,如果为使用寄存器的CPU编译它。基于堆栈的机器可能表现不同,因为操作仍然需要推送和弹出它们的操作数。