3

RAIIでは、リソースはアクセスされるまで初期化されません。ただし、多くのアクセスメソッドは定数として宣言されています。mutableデータメンバーを初期化するために(非const)関数を 呼び出す必要があります。

例:データベースからのロード

struct MyClass
{
  int get_value(void) const;

  private:
     void  load_from_database(void); // Loads the data member from database.

     int m_value;
};

int
MyClass ::
get_value(void) const
{
  static bool value_initialized(false);
  if (!value_initialized)
  {
    // The compiler complains about this call because
    // the method is non-const and called from a const
    // method.
    load_from_database();
  }
  return m_value;
}

私の基本的な解決策は、データメンバーをとして宣言することmutableです。他の方法でメンバーを変更できる可能性があるため、これは行いません。

load_from_database()コンパイラエラーを取り除くためにステートメントをキャストするにはどうすればよいですか?

4

6 に答える 6

20

これはRAIIではありません。RAIIでは、コンストラクターで初期化することで、問題を解決します。

したがって、ここで使用しているのはLazyです。怠惰な初期化であろうと怠惰な計算であろうと。

あなたが使用しない場合mutable、あなたは傷ついた世界にいます。

もちろん、を使用することもできますがconst_cast、誰かが使用した場合はどうなりますか?

static const MyClass Examplar;

そして、コンパイラはそれが読み取り専用メモリの良い候補であると判断しますか?さて、この場合、の影響const_castは定義されていません。せいぜい、何も起こりません。

const_castそれでもルートを追求したい場合は、同じように行ってR Samuel Klatchkoください。

よく考えて、より良い代替案があると思われる場合は、変数をラップすることを決定できます。get、、、の3つのメソッドのみを使用して独自のクラスにある場合は、それがであるsetload_from_databaseどうかを心配する必要はありませんmutable

于 2010-03-19T16:44:20.873 に答える
5

基本的に、キャッシュメカニズムを実装しています。個人的には、キャッシュされたデータを変更可能としてマークしても問題ないと思います。

于 2010-03-19T16:47:02.623 に答える
5

Matthieuがすでに指摘しているように、ここでやろうとしていることは、RAIIとはほとんど関係がありません。同様に、との任意の組み合わせが本当に役立つconstとは思えません。タイプを変更し、そのタイプのオブジェクトへのすべてのアクセスに等しく適用します。mutableconstmutable

必要と思われるのは、少量のコードに書き込みアクセス権を持たせ、それ以外のコードには値への読み取りアクセス権のみを持たせることです。C ++(およびほとんどの同様の言語)の基本設計を考えると、それを行う正しい方法は、変数を独自のクラスに移動することです。その一部として書き込みアクセスが必要な少量のコード(またはその友人)を使用します。 )そのクラス。その他の地域では、クラスのインターフェイス(つまり、値を取得するメンバー関数)を介して読み取り専用アクセスが許可されます。

MyClassあなたが投稿した(おそらく削除された)はかなり右に近いです-あなたは他の多くのメンバーがいるより大きなクラスの一部としてではなく、それ自体を使用する必要があります。主に変更するのは、1)名前をからのようなものに変更することMyClassですlazy_int。2)(少なくとも私の好みでは)get_value()名前をに変更する必要がありoperator int()ます。はい、m_valueおそらく可変である必要がありますが、他のコードが値自体にまったくアクセスできないという理由だけで、他のコードが値を書き込むことはできません。

次に、そのタイプのオブジェクトをより大きなクラスに埋め込みます。その外部クラスのコードは、そのおかげで(読み取り専用で)intとして扱うことoperator int()ができますが、クラスがそうする方法を与えていないという理由だけで、それを書くことはできません。

于 2010-03-19T18:15:15.797 に答える
4

[LOOK MA!キャストなし!:))]

struct DBValue 
{
  int get_value();

private:
  void load_from_database();
  int value;
};

struct MyClass 
{
  MyClass(): db_value(new DBValue()) {}
  ~MyClass() { delete db_value; } 

  int get_value() const;

private:
  DBValue * const db_value;
};

int MyClass::get_value() const
{
  return db_value->get_value(); // calls void load_from_database() if needed
}

アイデアは、何も変更せずに、 constポインターを介して集約オブジェクトの両方のメソッドと非メソッドを呼び出すメソッドを使用して、政治的に正しいものMyClassにすることです。constconstconst

于 2010-03-19T17:29:18.583 に答える
1

ここではconst_castを使用しないでください。使用すると、問題が発生します。この場合にミューテイタブルを使用することは問題ではありませんが、プロファイラーが別の方法を提案しなかった場合、ユーザーは、最初に呼び出すのに費用がかかるアクセサーメソッドよりも構築に費用がかかるオブジェクトを見て驚くことは少ないと思います。

于 2010-03-19T16:57:00.167 に答える
0

メソッドがオブジェクトの状態を変更する場合(たとえば、基になるデータベースの状態を変更することによって)、メソッドはconstであってはなりません。その場合、 getterをload呼び出す前に呼び出す必要がある、別のnon-constメソッドが必要です。const

この方法では、どちらも必要ではconst_castなくmutable、潜在的にコストのかかる操作を明示的にします。

于 2010-03-19T16:57:12.967 に答える