2017-01-01 3 views
0

グラフは、隣接行列または隣接リストとして表すことができます。私のGraphオブジェクトは、グラフを隣接行列として表します。パフォーマンス上の理由から、要求されない限り、隣接リストを計算しません。しかし、いったん要求されると、私はリストを保持して(再構築を避けるために)したいと思います。「ジャスト・イン・タイム計算」は、変更可能なものに適していますか?

隣接リストをmutableにするのが適切です。そうすれば、ユーザーは隣接リストをconstGraphのオブジェクトとして生成できますか?私は隣接行列を構築することがGraphの状態への "論理的な"変更とは対照的に、 "物理的な"ものとみなされるとは確信していないからです。私もadjacencyListBuiltメソッドを持っているので、隣接リストの構築は "不可視"ではありません(https://isocpp.org/wiki/faq/const-correctness#mutable-data-members参照)。

adjacencyListインスタンス変数mutableを宣言すると、の任意のメソッドがそれを更新できるようになります。 constオブジェクトのadjacencyListインスタンス変数をbuildAdjacencyListメソッドでのみ変更できる方法はありますか?

+1

あなたの最後の質問に - 他の方法では触れないでください。あなたはクラスの作成者です。誰もあなたの腕をねじって 'buildAdjacencyList'の外側で' adjacencyList'を修正していません。 –

+1

'adjacencyListBuilt'の目的は何ですか?発信者はこの情報をどのように使用する予定ですか?これは、呼び出し側とは関係のない実装の詳細を公開するように思えます。それを取り除き、 'getAdjacencyList()'の結果のキャッシュとして働くメンバーに 'mutable'を使うことは非常に合理的になります。 –

+0

'adjacencyListBuilt'は' assert'ステートメントでのみ使用されます。 'getAdjacencyList'が呼び出されるたびにリストがビルドされているかどうかを調べるのではなく、プログラマーが必要に応じてビルドを要求します。 (はい、私はこの小切手を取り除くことのメリットが非常に小さいことを知っています) – Zack

答えて

7

mutableを使用して内部メンバーから計算した結果をキャッシュすることは適切です。スレッドの安全性を損なう可能性があることに注意してください。

しかし、constオブジェクトで計算を実行する別のクラスまたは関数も考えてみましょう。

1

"ジャストインタイム計算"は正確にmutableが発明されたものなので、適切です。インターフェイスは特にそれを構築することを要求しないことに注意してください。 にアクセスを要求すれば、クラスはそれがまだ構築されていないことに気づき、それを「裏口」で構築します。したがって、論理状態はではなく、になります。

ビルディングを要求する機能と、ビルディングがまだ要求されていないときに呼び出すことができない機能またはアクセス機能のセットを考えている場合は、間違っています。この問題は、インターフェイスにあり、実装上では発生しません。したがって、mutableを使用して実装するかどうかにかかわらず、間違っています。

他の方法からそれをさらに保護する方法について:正しいことを理解していれば、隣接リストにはこれまでに行うべき2つのことがあります。現在の隣接行列から計算するか、無効にする必要があります。したがって、私は、可変メンバーをカプセル化して(それ自身が可変ではないメンバー変数として使用される)独立したクラス(Graphクラス専用)にカプセル化し、2つの操作のみを提供することを提案します。 const関数、まだ計算されていない場合はリストを計算します)、(2)リストを無効にします(グラフの変更だけが無効になります)。そうすれば、Graphクラスのconstメンバー関数はリストを変更できません。

2

buildAdjacencyListメソッドだけがconstオブジェクトのadjacencyListインスタンス変数を変更できる方法はありますか?ネストされたプライベートメンバーとfriendを使用して確かに

、:それは私の特定のケースでは、変更可能な作りのものがかなり速い総なった非常に多くの異なるキャッシュされた値があった、判明したように

class myGraph; 
void buildAdjacencyListImpl(const myGraph&); 

class myGraph 
{ 
    class myAdjacencyListCache 
    { 
     mutable realAdjacencyList cached_list; 

     friend void buildAdjacencyListImpl(const myGraph&); 
    } adj_list; 
    friend void buildAdjacencyListImpl(const myGraph&); 

    void buildAdjacencyList() const { buildAdjacencyListImpl(*this); } 
}; 

void buildAdjacencyListImpl(const myGraph& g) 
{ 
    realAdjacencyList& listToBuild = g.adj_list.list_cache; 
    // it isn't const, and can be modified 
} 
1

。 (上記の説明は簡略化されました)代わりにGraphのとMutableGraphという2つの異なるバージョンを作成することにしました。 ImmutableGraphには、エッジや頂点を追加または削除するメソッドがありません。したがって、ImmutableGraphconstと宣言されるべき場合がほとんどありません。

関連する問題