5

私たちのプロジェクトで不可解な問題を検出した後、私はまだショックを受けています.

HasMember("string") を呼び出すと余分なシークが実行されることに気付きました。したがって、パフォーマンス上の理由から、変更します。

主なアイデアは次のとおりです。

HasMember を呼び出してから、次のように参照をプリキャッシュする代わりに:

rapidjson::Document d;
d.Parse<0>(json);

if(d.HasMember("foo"))
{
    const rapidjson::Value& fooValue = d["foo"];

    // do something with fooValue
}

変更:

rapidjson::Document d;
d.Parse<0>(json);

const rapidjson::Value& fooValue = d["foo"];
if( !fooValue.IsNull() )
{
    // do something with fooValue
}

これはかなり良かったです。シークを 1 回だけではなく 2 回実行するように保存します。しかし、ここで問題が発生します。

Rapidjson が nullvalue (シークが失敗したときにデフォルトで返される) を実装する方法を調べ始めると、次のコードが表示されます。

//! Get the value associated with the object's name.
GenericValue & operator[](const Ch* name) {
    // Check
    if (Member * member = FindMember(name)) {
        return member->value;
    } else {
        // Nothing
        static GenericValue NullValue;
        return NullValue;
    }
}

// Finder
const GenericValue & operator[] (const Ch* name) const { 
    // Return
    return const_cast<GenericValue &> (* this)[name]; 
}

そのため、メンバーが見つからない場合は、ローカルの静的変数を返します。これは一見すると十分に聞こえるかもしれませんが、これは参照によって返されるため、隠れたバグに簡単につながる可能性があります。

誰かが静的な NullValue の参照を変更したとします。これにより、NullValue が別の型またはランダム メモリに変更されるため、IsNull への以降のすべての呼び出し (検索後) が失敗します。

それで、あなたは何をしますか?これはヌル パターンの良い例だと思いますか?

私は混乱しています。デフォルトの null 値を返すという考えは好きですが、const として返されないため、これは危険です。また、すべての場合に const として返す場合でも、開発者は引き続き const_cast を使用できます (ただし、そうする場合、開発者が責任を負うことになるとは思いません)。

このような他のケースや例を聞きたいです。そして、誰かがrapidjsonコードの下で実際のソリューションを提供できれば、基本的に素晴らしくて驚くべきものになるでしょう.

4

1 に答える 1

9

この設計の落とし穴は、ずっと前にコミュニティによって提起されました。operator[]非 const バージョンも必要であるため、静的変数の整合性を維持することはできません。

そのため、この API は RapidJSON の新しいバージョンで変更されました。存在しないキーのoperator[]単純なアサート。キーが存在するかどうかわからない場合は、使用することをお勧めします

MemberIterator FindMember(const Ch* name);
ConstMemberIterator FindMember(const Ch* name) const;

そして値を比較してMemberEnd()、キーが存在するかどうかを確認します。これはここにも文書化されています。

また、RapidJSON はGitHubに移動されていることに注意してください。多くの問題が解決されました。可能であれば最新版をご利用ください。ありがとうございました。

PS 私は RapidJSON の作成者です。

于 2014-10-08T01:37:54.597 に答える