3

C++ で分散マップを実装し、適切な API 設計を探しています。最初の簡単なオプションは、std::map とまったく同じにすることです。問題はイテレータにあります。

IMap<std::string,Person>::iterator it;
it =  map.find("sample");
if(it == map.end() ){
    //NULL
}
for(it = map.begin(); it != map.end(); it++){
    //iterate
}

分散コンテキスト(少なくとも私が実装しているコンテキスト)では、マップの開始と終了はありません。とにかく順序付けされていないため、イテレータを返すことはオプションのようには見えません。

2 番目のオプションは、以下のように値クラスをコピーして返すことです。

Person emptyPerson; 
Person person = map.get("sample");
if(person == emptyPerson){
    //NULL
}

問題は、NULL チェックが奇妙に見えることです。最初にオブジェクトが使用可能かどうかを尋ねてからオブジェクトを取得できますが、これらの操作はアトミックである必要があります。

3番目のオプションはポインタを返すことです:

Person* person = map.get("sample");
if(person == NULL){
    //NULL
}

エラーが発生しやすいため、この方法は使用したくありません。ユーザーは、内部で作成したポインターを削除する必要があります。

次のようなユーザーオブジェクトをラップするクラスを返すことを考えています:

value_reference<std::map, Person>  person = map.get("sample");
if(value_reference.hasValue() ){
    Person p = value_reference;
}

では、最善のアプローチは何だと思いますか?

私の分散マップの要件に似た良いAPIを知っていますか?

4

2 に答える 2

1

「分散マップ」という用語に基づいて、次の仮定を立てています。

  • データのサブセットはローカルで利用できます。一部のリモート フェッチではないデータ セットについては、実行する必要があります。
  • 返されたオブジェクトへの書き込みは、データ ストアに自動的に保持されません。代わりに、明示的な更新リクエストを行う必要があります。

これが当てはまる場合、イテレータは必要なものではなく、STL コンテナー モデルも必要ありません。C++ イテレータの概念では、プレインクリメント ( ++i) 演算子を実装する必要があり、データが順序付けられておらず、複数のノードに分散している場合、「次のエントリをくれ」という要求は意味がありません。

相互運用性の理由で STL コンテナーとイテレーターをシミュレートしたい場合、ひどい混乱を引き起こす可能性があります。マップのend()メソッドにセンチネル イテレーター インスタンスをoperator++()返させ、イテレーターにこれと同じセンチネルを返すようにさせます。事実上、すべての反復子は「マップ内の最後の要素」を指します。必要にならない限り、このアプローチを採用しないことを強くお勧めします。また、そうなるとは思いません。

更新を明示的に要求する必要がある単純な CRUD モデルが必要なようです。その場合、API は次のようになります。

template <typename TKey, typename TValue>
class IMap<TKey, TValue>
{
public:
    void create(TKey const & key, TValue const & value) = 0;
    std::unique_ptr<TValue> retrieve(TKey const & key) = 0;
    bool update(TKey const & key, TValue const & value) = 0;
    bool remove(TKey const & key) = 0;
};

取得の場合、提案したように null ポインターを返すだけです。 std::unique_ptr<>呼び出し元が割り当てられたオブジェクトを削除するか、明示的に所有権を取得することを保証します。

「新しく割り当てられたオブジェクトへのポインターを返す」ケースの代替は、呼び出し元に参照を渡すことであり、値がマップで見つかった場合、メソッドは true を返します。これにより、たとえば、呼び出し元は、中間ヒープ割り当てを必要とせずに、オブジェクトを配列スロットまたは他のローカル構造に直接取得できます。

bool retrieve(TKey const & key, TValue & value) = 0;

このメソッドを使用すると、次のようになります。

Person person;

if (map.retrieve("sample", person)) {
    std::cout << "Found person: " << person << std::endl;
} else {
    std::cout << "Did not find person." << std::endl;
}

両方のオーバーロードを提供することもできます。ポインターを返すものは、デフォルトでもう一方の観点から実装できます。

template <typename TKey, typename TValue>
std::unique_ptr<TValue> IMap<TKey, TValue>::retrieve(TKey const & key)
{
    TValue v;
    return std::unique_ptr<TValue>(retrieve(key, v) ? new TValue(v) : nullptr);
}
于 2013-08-21T21:06:50.623 に答える