【问题标题】:Find and return by reference in STL map在 STL map 中通过引用查找并返回
【发布时间】:2017-09-19 06:53:49
【问题描述】:

我有一个包含这两个公共方法的类:

void StateManager::setEntityState(const EntityCTCId id, const EntityCTCState state) {
    auto it = entities.find(id);
    if(it != entities.end())
        it->second.state = state;
    else
        entities.emplace(id, EntityCTC{id, state});
}

EntityCTCState StateManager::getEntityState(const EntityCTCId id) const {
    auto it = entities.find(id);
    if(it != entities.end())
        return it->second.state;

    std::stringstream ss;
    ss << "Entity CTC [" << id << "] NOT found!";
    throw EntityCTCNotFound{ss.str()};
}

其中entitiesstd::map&lt;EntityCTCId, EntityCTC&gt;

我想重构这些方法以隔离常见的find 并通过引用返回找到的EntityCTC,但我不知道如何处理“找不到密钥”的情况:

EntityCTC& findEntity(const EntityCTCId id) {
    auto it = entities.find(id);
    if(it != entities.end())
        return it->second.state;
    else
        // ???
}

我找到的唯一解决方案是在这个新方法中抛出异常,但这意味着在setEntityState 中使用try-catch 来区分更新和新插入(我读到异常管理不应该用作逻辑分支,但仅用于错误管理)。

您能建议我其他方法吗?

【问题讨论】:

  • 在我看来你过度重构了。如果每个函数的目标不同,我认为在两个不同函数中调用同一张地图上的 find() 没有问题。
  • 怎么样: bool findEntity(const EntityCTCId id, EntityCTC &state) ?此外,返回引用不是一个好习惯,因为 id 可能会从实体中删除。
  • entities.at 用于get 和StoryTeller 的建议(或operator[])用于set 有什么问题?为什么EntityCTCNotFound 是由std::string 而不是EntityCTCId 构造的?

标签: c++ c++11 stl c++14


【解决方案1】:

另一种方法是充分利用 API。如您所见,emplace 有一个返回值。这是std::pair&lt;iterator, bool&gt;。迭代器可以用来访问key下的item,bool是让你知道是否有插入发生或者key已经存在于map中。

所以,我建议你改写setEntityState

void StateManager::setEntityState(const EntityCTCId id, const EntityCTCState state) {
    auto status = entities.emplace(id, EntityCTC{id, state});
    if(!status.second)
      status.first->second.state = state;
}

现在无需担心通用功能,您只需在函数中执行一次 O(logN) 操作,而不是两次。


附录,因为您可能担心构造值的成本,而不是作为过早优化的一部分。充分利用 API 的另一点是要知道有办法分段构造插入到地图中的对。像这样:

auto status = entities.emplace(std::piecewise_construct,
                               std::forward_as_tuple(id),
                               std::forward_as_tuple(id, state));

【讨论】:

  • 但是现在即使没有必要,您也必须始终构建EntityCTC
  • @nwp - 是吗?复制省略是一回事。
  • 是的。如果给定的id 已经存在于entities 中,则原始代码不会创建EntityCTC 而您的代码会创建EntityCTC。复制省略不会让你摆脱困境。
  • @nwp - 我不知道 OP 的状态有多简单,所以你所说的 可能 是过早的优化。但无论如何,如果需要,我们可以分段构造该对。
  • @Caleth - 需要默认的 c'tor。不想假设。
猜你喜欢
  • 2016-08-25
  • 1970-01-01
  • 1970-01-01
  • 2014-12-11
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
  • 2013-03-13
  • 1970-01-01
相关资源
最近更新 更多