STLやDirectXなどを使い出すと意外な所で一時オブジェクトが発生しています。
今日はD3DXVECTOR3の隠れた一時オブジェクトを紹介します。
[0回]
①と②どっちが早いでしょう~?
D3DXEVCTOR3 v,v1,v2;
①
v=v1+v2;
②
v+=v1;
v+=v2;
---解説---
①の場合
D3DXVECTOR3のoperator+が呼ばれます。
D3DXVECTOR3 D3DXVECTOR3::operator+(const D3DXVECTOR3& vec)
{
return D3DXVECTOR3(this->x+vec.x,this->y+vec.y,this->x+vec.y);
}
D3DXVECTOR3の一時オブジェクトがreturn文の所でよばれてしまい、
インスタンスが発生するとともに、
D3DXVECTORのコンストラクタが呼ばれます。
コンストラクタの引数でthis->x+vec.xでも計算結果が発生します。
②の場合
D3DXVECTOR3& D3DXVECTOR3::operator += ( const D3DXVECTOR3& v )
{
this->x += v.x;
this->y += v.y;
this->z += v.z;
return *this;
}
D3DXVECTOR3の一時オブジェクトの発生しないです。
ということで②が早いです。
早くなるのは確かですが、ほんの少しです。毎ループするところとかはちょっと意識するのもいいですね。
ここからが本題です。GESリーダの本気です。
これから紹介する内容は難しい所があります
v=v1+v2;
をD3DXVECTOR3の一時オブジェクトが発生しないような方法があります。
その名は
式テンプレート。
式の情報をクラスとして保持し、=が呼ばれたときに初めて計算を始める遅延評価的なことをしていきたいとおもいます。
まずはじめにデフォルトの仕様から、
v=v1+v2;
これはv1がoperator+を呼び出し、足し算した結果をD3DXVECTOR3として返します。
v=(D3DXVECTOR3);
こういう感じです。
今回はこうなります。
v=(VPlus);
自分とは違う型を返しているところが違和感であり、ポイントです。
では解説してきます。
class CVector3 : public D3DXVECTOR3
{
public:
VPlus operator+(CVector3 _r){ retrun VPlus(*this,_r); }
template<class T> CVector3& CVector3::operator=(const T& _vp)
{
_vp.ret(*this);
return *this;
}
static void Plus( CVector3& _dest, const CVector3& _l, const CVector3& _r)
{
_dest.x+=_l.x+_r.x;
_dest.y+=_l.y+_r.y;
_dest.z+=_l.z+_r.z;
}
};
class VPlus
{
private:
const CVector3& m_l;
const CVector3& m_r;
public:
VPlus(const CVector3& _l, const CVector3& _r):
m_l(_l),m_r(_r){}
void ret(CVector3& dest) const
{
CVector3::Plus( dest,m_l, m_r );
}
};
CVector3のoperator+が呼ばれた時にVPlusを返し、=が呼ばれた時ret関数を呼び初めて計算しています。
こうすることによってD3DXVECTOR3の一時オブジェクトが発生しなくなりました。
現状だと、この実装をしないほうが早くなるし、v=v1+v2+v3;でコンパイルエラーになります。
あくまで式テンプレートの触りだけを紹介しました。
もっと詳しく知りたい方は「
http://homepage1.nifty.com/herumi/prog/prog81.html」
私はここで勉強しました。
boostのprotoで式テンプレートを作る際の補助ライブラリとして提供されているそうです。
以上誰得情報でした~。
byリーダ和田
PR
COMMENT
No Title
他にもラムダ式や、バグをなくさせるための工夫など、色々有用なものが増えているみたいです。
業界もこちらに移っていきそうですね。
No Title
「右辺値参照」なんですか
「不変値参照」と聞き間違えていて出ないなと困ってました
いつになるかわからないですが、
また会える日を楽しみにしています!