アクションの履歴(元に戻る/やり直し)とシリアル化を本質的にサポートする必要があるシステムを設計しています。さまざまなエンティティが含まれており、その多くはグラフとしてリンクされています。
オブジェクトの作成、破棄、リンクについてアクションに通知することで、ほとんどの履歴ログ作業を自動化したいと思っています。私が直面している問題は次のとおりです。
オブジェクトAを作成し、次にオブジェクトBを作成し、次にAとBをリンクするとします。これらは3つのアクションです。すべてを元に戻すと、アクションは「やり直し」リストに移動します。ここで、すべてをやり直します。これは、新しい Aオブジェクトが作成され、新しい Bオブジェクトが作成されることを意味します。また、リンク操作をやり直すには、古い AオブジェクトとBオブジェクトに作用した「リンク」アクションが新しい AオブジェクトとBオブジェクトに適用されることを知る必要があります。
単純な再配置テーブルでうまくいきます。新しいオブジェクトを作成するときは、古いアドレスを新しいアドレスにマップし、それを使用して履歴ログからのリンク関係を解釈します。問題は、多重継承が関係している場合はどうなるかということです。つまり、リンクはA自体ではなく、Aのベースへのポインタを参照している可能性があるため、アドレスは再配置テーブルのアドレスとは異なる可能性があります。
システムは数百GBのメモリを処理する必要があるため、パフォーマンス上の理由から、すべてのポインタを内部で破棄してグローバルな一意のIDに切り替え、常にテーブルルックアップを実行するのではなく、一部のタイプは非常に軽量であるため、すべての仮想基本クラスをスローすることも望ましくありません。
問題は、私が言及した2つの選択肢以外に、(おそらく複数の)基本クラスの1つへのポインターを介してオブジェクトを一意に識別することは可能ですか?これを自動化し、関係するタイプごとに専用のコードを書くことをあきらめる必要がありますか?
編集:
たぶん私は長い説明で十分に明確ではありませんでした。問題を示す簡単な例を次に示します。
#include <iostream>
using namespace std;
struct A { int x; };
struct B { int y; };
struct AB : A, B { int z; };
int main()
{
AB ab;
AB* pab = &ab;
A* pa = &ab;
B* pb = &ab;
cout << "pab: " << pab << endl;
cout << "pa: " << pa << endl;
cout << "pb: " << pb << endl;
}
考えられる出力の1つは次のとおりです。
pab: 0x7fff30b6a400
pa: 0x7fff30b6a400
pb: 0x7fff30b6a404
ご覧のとおり、同じオブジェクトからのものであっても、とpb
は異なる値を持っています。pab
両方が同じオブジェクトを識別することを知る方法が必要です。理由は上記で説明しました(do / undo操作はオブジェクトを新しい場所に再作成する可能性があるため、オブジェクトへのすべてのポインターを更新する必要があります)。