9

コンストラクタ/デストラクタ以外で何もしないクラスがいくつかあります。これが例です

class BusyCursor 
{
  private:
    Cursor oldCursor_;

  public:

    BusyCursor()
    {
      oldCursor_ = CurrentCursor();
      SetCursor(BUSY_CURSOR);
    }
    ~BusyCursor()
    {
      SetCursor(oldCursor_);
    }
}

// example of use
    void DoSlowThing
    {
      BusyCursor busy;
      ... do something time-consuming  ...
    }

今後の可読性が少し気になります。コードで実際に使用されることのない変数 (「ビジー」) を使用して、ここで「トリッキー」すぎますか? いくつかの静的分析ツールは、それらが削除されることを示唆する可能性がありますか?それとも、このイディオムは心配する必要がないほど一般的ですか?

4

9 に答える 9

36

この手法は非常に一般的であり、デザイン パターンResource Acquisition Is Initialization (RAII)として知られています。

このデザインパターンを使用することを躊躇しません。

カーソルのリセットを忘れたり、問題のリソースが何であれ、バグを回避できるため、この設計パターンを使用してコーディングする方がはるかに優れています。

他のプログラマーが理解できないのではないかと心配しているなら、それらのプログラマーはもっと教育を受けるべきです。最もエラーのない方法でコードを作成するよう常に努力してください。自分自身や他の人が自分自身や自分自身を撃つことができないようにします。


「いくつかの静的分析ツールは、それらが削除されることを示唆できますか?」

  • これを問題と見なす静的解析ツールはありません。
  • コンパイラの警告は表示されません
  • コンパイラの最適化によって問題が発生することはありません。

その理由は、オブジェクトが作成され、コンストラクター/デストラクターが呼び出されるためです。したがって、参照されていない変数ではありません。

于 2009-01-12T12:55:30.973 に答える
10

他の人が言っているように、これは良いC++スタイルです。読みやすくするために、私は常にそのようなRAIIのみのクラスの前にScoped(たとえばScopedBusyCursor)を付けて、クラスの目的が何であるかを一目で明確にします。

于 2009-01-12T13:41:22.517 に答える
7

これは、他の人が答えたように、よく知られた優れたC++イディオムです。

クラスがスコープ内でのみ使用され、異なるスコープ間で移動されないように意図されていることを明確にするために、クラスをコピー不可にすることをお勧めします。これは、未実装のプライベート コピー コンストラクターとコピー代入演算子を追加することで手動で行うことができます。より短く読みやすい方法は、クラスをboost::noncopyableから派生させることです。

#include <boost/noncopyable.hpp>
class BusyCursor : public boost::noncopyable // for scoped use only
{
    // ...
};
于 2009-01-12T13:54:35.330 に答える
4

間違いなく、このパターンを使用しないのは悪いイディオムです。RAIIを使用していない場合、コードは次のようになります。

void func() {
    Cursor oldCursor = CurrentCursor();
    SetCursor(BUSY_CURSOR);
    try {
        do_slow_stuff();
        SetCursor(oldCursor);
    } catch (...) {
        SetCursor(oldCursor);
        throw;
    }
}

コード全体に散らかっている方がメンテナンスに適していると本当に思いますか?

于 2009-01-12T13:42:46.493 に答える
4

よく使われるイディオムです。

たとえば、時間のかかるコードが例外をスローした場合でも、~BusyCursorデストラクタは引き続き呼び出されます。

于 2009-01-12T12:57:51.763 に答える
3

変数が使用されているため、変数を削除することを提案する正気の静的分析ツールはありません。コンストラクタとデストラクタが呼び出されるため、効果があります。あなたは完全に安全であるべきです。

于 2009-01-12T12:59:48.717 に答える
3

他の人は、これが従来の RAII であると既に述べています。付け加えておきますが、これは C++ の最も優れた点の 1 つです。それをサポートしている、または少なくとも適切にサポートしている他の言語はほとんどありません (C# の using コンストラクトでさえ、クライアント コードに負荷がかかるため、それほど良くありません -これに関する私のブログ エントリを参照してください)。

これは C++ と非常に密接に関連しているため、これを読んでいる人なら誰でも C++ に精通していると確信できるはずです。

于 2009-01-12T13:36:06.913 に答える
2

私は通常、これを「ガード」と呼んでいます。私の意見では、これは C++ の最大の強みの 1 つ (決定論的なリソース処理) を示しています。これは、ガーベッジ・コレクトされた言語で作業しているとき、私が最も見逃していることの 1 つです。

于 2009-01-12T13:14:44.443 に答える
0

Andrei Alexandrescu と Petru Marginean によるScopeGuardのようなものを使用することもできます。サンプルは次のようになります。

void DoSlowThing
{     
    Cursor oldCursor = CurrentCursor();
    SetCursor(BUSY_CURSOR);
    ON_BLOCK_EXIT(SetCursor, oldCursor);
    ... do something time-consuming  ...
}

これにより、1 回限りの RAII タイプの操作を簡単に実行できるようになり、操作ごとに新しいクラスを作成する必要がなくなります。ただし、 Cursor の例では、何度も再利用する可能性が高いクラスであるため、専用クラスを使用する方がよいでしょう。

于 2009-01-16T23:57:20.753 に答える