ゲームプログラマのための設計シリーズ :実装詳細編の記事です。
概要
- RVO(Return Value Optimization)で、戻り値の一時オブジェクトの生成が抑制される
- 純粋関数を活用するのにRVOが役立つ
- 一方NRVOはオススメしない
本文
RVOはオススメ
以下の記事にて、「純粋関数」を積極的に利用しようと紹介しました。
https://qiita.com/kobitnex/items/b7093143d06029021b93
純粋関数とは、
int PureFunc(int)
{
// グローバル変数を読み書きしない
// 引数に可変参照をとらない
// 非メンバ関数である
return ...;
}
このようなものでした。
ここで気になるのが帰り値でサイズの大きなクラスを返す際のコピーコストですが、これを削除してくれるのがRVO(Return Value Optimization)です。
BigData PureFunc(int)
{
return BigData(); // この関数の戻り値で変数を初期化するとき、コピーが発生しないようにしてくれる
}
RVOの何よりうれしいところは、
- C++17より規格に取り込まれているのでコンパイラやオプションによらず確実に行われる
- コピー/ムーブが実際に行われないだけでなく、そもそもコピー・ムーブコンストラクタがないクラスでも返せる
点にあります。
// コピー・ムーブ不可のクラスでもOK
class BigData
{
public:
explicit BigData() = default;
BigData(const BigData&) = delete;
BigData(BigData&&) = delete;
};
実行速度パフォーマンスを落とさず良い設計を保てるオススメの機能です。
NRVOはオススメではない
類似の最適化として、NRVO(Named Return Value Optimization)というものがあります。その名の通り、名前がついている(左辺値)変数を返した場合にも同様の最適化を施すというものです。
こちらは規格では保証されていないので、必ず実行されるとは限らない、コピー不可のオブジェクトは返せないというデメリットがあります。
BigData PureFunc(int)
{
BigData data{};
return data; // BigDataがコピー不可だとコンパイルエラー
}
このスタイルを利用するということは事実上帰り値がconst変数ではないということになるので、その点でもあまりお勧めしません。