ゆとりーなの日記

日記的な事を書いて行くと思はれる

脳が一旦C++モードに入ると他の事がつい疎かになる

graphic::begin_scene、graphic::end_sceneの呼び出しはRAII的なサムシングにした方がC++っぽいのではという話です。途中で例外とかが飛んでもちゃんとgraphic::end_sceneは呼びたいですからね。

namespace {
class scoped_render : private boost::noncopyable {
 public:
  scoped_render() {
    if (begin_scene()) {
      throw std::runtime_error("描画開始に失敗");
    }
  }
  ~scoped_render() {
    end_scene();
  }
};
}

最初はgraphic::presentもふくめたRAIIにしようと思ったのですが、デバイスロストで復旧が出来そうもない時は例外を投げたいのでデストラクタから飛び出る例外を出すのはどうなのということで止めました。画面に実際に描画するタイミングを制御出来ていい気もします。まあでもDirect3D9の仕様上出来る限りgraphic::end_sceneの直後に呼んでほしいというのはあるのですが。
一つ気になっているのがコンストラクタでの例外です。私自身コンストラクタが投げる例外に関しては肯定派に立っているので投げること自体は別に悪いことだとは思っていません。しかも今回の場合は例外が飛んでデストラクタが呼ばれなくても全く困りません。というよりむしろ歓迎したいくらいです。今回の場合投げるのが妥当かという点が問題になります。まず、graphic::begin_scene関数はIDirect3DDevice9::BeginSceneメソッドを呼び出しているのでこいつがどれくらい失敗するのかをみる必要もあります。デバイスロスト中に呼び出された時位な感じがします。あとはIDirect3DDevice9::BeginSceneが二重に呼び出されていた時ですね。まあ描画開始が出来ないわけだから契約を満たせない基準で例外を投げてもよさそうですがこれ、ゲームを終了させるほどの致命的なあれではないですよね。デバイスロストから復帰できれば描画開始が再開できる訳ですし。そうなるとここではコンストラクタが出す例外をキャッチしてもなにもしないコードを書く必要があるわけになります。またそうなると、他の例外と区別するためにも、std::runtime_errorを継承した何か別の例外クラスを用意してそいつを投げた方がいいです。
こんな雰囲気のクラスのコンストラクタで例外を投げるってどうなの?というのが今の私の心境です。graphic::begin_sceneがboolを返すように設計したのもそういう意図があったわけで。まあ結構IDirect3DDevice9::BeginSceneの戻り値チェックしていないコードもありますし、失敗してても描画メソッドが勝手に失敗してくれるということを考えると、極論言えば無視して良くないかと言えなくもないですが、やっぱり描画開始に失敗した時は描画メソッド呼び出しをすっとばした方が綺麗ですよね。