2016-12-13 1 views
3

今日、私はC++でmutableというキーワードを学び、自分のコードで使ってみたいと思っています。「可変」変数はconstメソッドの1つでしか変更できませんか?

私は多くのconstメソッドを持つクラスを持ち、そのうちの1つはオブジェクトの変数の一部を変更できる(オブジェクトの論理状態を保存する)ことができるはずです。しかし、私はすべてのconstメソッドに変数を変更させたいだけでなく、選択したものだけを変更したいと思います。それを行う方法はありますか?たぶんconst_castで?

(私が話しているコードは、Union-Find structureの実装です。Findの操作では、構造の論理状態は変更されません(ツリーのルートのみが検索されます)が、物理状態が変更されます-called path compression)

ありがとうございます!

編集:私は、私が言及していたコードからの抜粋を追加しました:あなたはmutableを使用するために余裕があれば

class UnionFind { 
    public: 
    void Union(int a, int b) {...} 

    int Find(int x) const { 
     // logically, this method is const 
     while(x != parents[x]) { 
     // path compression 
     // the next three lines modify parents and sizes, 
     // but the logical state of the object is not changed 
     sizes[parents[x]] -= sizes[x]; 
     sizes[parents[parents[x]]] += sizes[x]; 
     parents[x] = parents[parents[x]]; 

     x = parents[x]; 
     } 
     return x; 
    } 

    int someOtherMethodThatAccessesParents() const { 
    // this method does access parents, but read only. 
    // I would prefer if parents behaved like if it was 
    // not 'mutable' inside this method 
    ... 
    } 

    private: 
    // these have to be mutable if I want the Find method 
    // to be marked const (as it should be) 
    // but making them mutable then does not enforce 
    // the physical non-mutability in other const methods :(
    mutable std::vector<int> parents; 
    mutable std::vector<int> sizes; 
}; 
+2

物理ブロックと論理ブロックについて学ぶhttp://stackoverflow.com/a/3830484/151641 – mloskot

+4

メンバーを変更可能と宣言した場合は、そのクラスのメソッドから変更できます。プライベートであると宣言して、サブクラスはそれにアクセスすることができず、優れたエンジニアリング手法を使用してルールを適用します。あなたのコードレビューがそのような誤用を拾うことができなければ、クラスが大きすぎるかもしれないことを示唆しています。 –

+0

私はこれまでプロダクションコードでmutableを使用していた唯一の時は、 'std :: mutex'をmutableとしてマークすることで、constメソッドは実行中の状態の変化を防ぐことができると確信しています。 –

答えて

-5

、それはそれを行うには正しい方法です。

まだ、あなたが求めていることは可能です。通常、これは「偽this」イディオムを介して行われます:

MyClass *mutableThis = const_cast<MyClass*>(this); 

次に、新しいポインタを通じて、通常は、あなたのフィールドにアクセスします。 mutableがサポートされていない古いコンパイラをサポートしなければならない場合にも、これを行う方法です。

しかし、これは一般的に危険な慣習です。恐らく未定義の動作の恐ろしい領域につながる可能性があります。元のオブジェクトが実際にconstポインタ/参照によってアクセスされるのではなく)constと宣言されている場合は、問題が発生する可能性があります。

要約すれば、可能であればmutableを使用してください。可能であれば、偽のthisを使用してください。あなたが行っていることが分かっている場合にのみ使用してください。

+2

私はdownvoterでした。あなたは未定義の振る舞いを奨励しているようですOPはconst関数はいくつかの変数を変更する必要があるので、 'const'関数を' const'関数内で ' – AndyG

+2

@AndyG厳密に言えば、変更された変数/オブジェクトがもともと 'const'として宣言されていたのはUBだけです。 –

+2

@JesperJuhl:本当に、私はそれを認めています。私はダウングレードしますm "これは危険であり、通常は悪いデザインを示しています"とコメントしています。あなたの "const"関数を呼び出そうとする 'const MyClass&_instance'メソッドを受け取ると、すぐに爆発します。 'mutable'は、論理的な状態ではなく物理的な状態を変更するための正しいアプローチです。さもなければ、誤解を招くので 'const'を削除してください。 – AndyG

3

あなたが厄介なconst_castを使用しない限り、一見するとこれは達成できません。 constとして宣言されたconst_castに続いて変数を変更しようとすると、その動作が定義されていないため、そのようにしないでください。

しかし、友情を使って欲しいものを達成するのは実現可能なのかもしれません。なぜなら、それは関数ごとに制御できるからです。

変更する変数を基本クラスに入れ、それを非公開にします。おそらくそのメンバーに「ゲッター」機能を提供します。その関数はconstであり、おそらくメンバへのconst参照を返すでしょう。次に、あなたの関数をその基本クラスの友人にします。その関数は、そのプライベートメンバーの値を変更することができます。

+0

これは質問されたように質問に答えます。もちろん、(派生した)クラスの他のメンバ関数も、それらが友達として宣言されていない限り、変更可能メンバの値にアクセスすることさえできません。それはメンバーの目的を最初に置き換えることを拒否するかもしれません。 – Peter

+0

@peter:そのため、私はconst関数が提供されることを提案しています。私が知っているかなりの定型文。 – Bathsheba

+0

@Bathsheba:コード例を追加しました。私はあなたの答えをまだ完全には理解していませんが、変数がconstとして宣言されていないので、const_castがこの場合に動作すると思われます。私はこれが厄介な解決策であると理解していますが、別のクラスは私にとってもっと厄介なようです。また、あなたのソリューションはランタイムオーバーヘッドをゼロにしますか?ご協力いただきありがとうございます! – serycjon

関連する問題