【问题标题】:C++ rapidjson: GenericValue::IsNull is returning false in any caseC++ rapidjson:GenericValue::IsNull 在任何情况下都返回 false
【发布时间】:2014-10-06 18:02:17
【问题描述】:

在我们的项目中发现一个神秘问题后,我仍然感到震惊。

我们意识到调用 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 如何实现 nullvalue(在 seek 失败时默认返回),你会看到以下代码:

//! 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 更改为另一种类型,甚至更改为随机内存。

那么,你喜欢什么?你认为这是一个很好的空模式示例吗?

我很困惑,我喜欢返回默认空值的想法,但由于不作为 const 返回,这很危险。而且,即使我们在所有情况下都将其返回为 const,开发人员仍然可以使用 const_cast(但我不认为,如果他们这样做,将由他们负责)。

我想听听像这样的其他案例和例子。如果有人能在 rapidjson 代码下给出一个真正的解决方案,那基本上就很棒了。

【问题讨论】:

  • if( !d.IsNull() ) 应该是if( !fooValue.IsNull() ) 对吧?
  • 对!已编辑,谢谢

标签: c++ performance design-patterns rapidjson


【解决方案1】:

这个设计的陷阱很久以前就被社区提出来了。由于operator[] 也需要非常量版本,所以无法保持静态变量的完整性。

因此,此 API 在较新版本的 RapidJSON 中已更改。 operator[] 只是断言不存在的键。如果不确定密钥是否存在,最好使用

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

并将该值与MemberEnd() 进行比较以检查该键是否存在。这也记录在here

此外,请注意 RapidJSON 已移至 GitHub。许多问题已经解决。如果可能,请使用最新版本。谢谢。

附:我是 RapidJSON 的作者。

【讨论】:

  • Milo 在哪里可以找到 rapidjson 0.2 版本?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-07
  • 2022-11-19
  • 2020-04-19
  • 1970-01-01
  • 1970-01-01
  • 2017-07-29
  • 2015-03-06
相关资源
最近更新 更多