Я до сих пор в шоке, обнаружив загадочную проблему в нашем проекте.
Мы поняли, что вызов 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
}
Это было довольно хорошо, мы экономим на выполнении двух поисков вместо одного. Однако здесь возникает проблема.
Если вы начнете смотреть, как Rapidjson реализует нулевое значение (возвращается по умолчанию при сбое поиска), вы увидите следующий код:
//! 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. Это приведет к тому, что все дальнейшие вызовы IsNull (после его поиска) завершатся неудачно, потому что NullValue изменился на другой тип или даже на случайную память.
Итак, что вы думаете? Как вы думаете, это хороший пример нулевого шаблона?
Я в замешательстве, мне нравится идея возврата значения null по умолчанию, но поскольку оно не возвращается как const, это опасно. И, даже если мы вернем его во всех случаях как const, разработчики все равно могут использовать const_cast (но я бы не ожидал, что если они это сделают, то будут под их ответственностью).
Я хочу услышать другие случаи и примеры, подобные этому. И если кто-то может дать реальное решение в коде rapidjson, это будет просто потрясающе и потрясающе.
if( !d.IsNull() )
должно бытьif( !fooValue.IsNull() )
правильно? - person Narek   schedule 24.03.2015