私たちのプロジェクトで不可解な問題を検出した後、私はまだショックを受けています.
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コードの下で実際のソリューションを提供できれば、基本的に素晴らしくて驚くべきものになるでしょう.