【问题标题】:Template class map build on stl::vector of structs - looking for invalid key(stl::string) and throwing an exception模板类映射建立在结构的 stl::vector 上 - 查找无效键 (stl::string) 并抛出异常
【发布时间】:2014-02-25 12:02:13
【问题描述】:

如标题所示,我正在尝试编写一个基于结构向量的模板类映射,其中我持有作为字符串的键和模板类型的值。有一个简短的主程序代表我的类的用法:

int main()
{
  map<int> iv;

  iv["john"] = 23;

  int ia = iv["john"]++;
  int ib = iv["john"];

  cout << ia << " " << ib << endl; // prints 23 24
  try{
  int ic = iv["jack"];  // should throw an exception
  }catch(map<int>::Uninitialized&)
  {
    cout << "Uninitialized map element!" << endl;
  };
}

还有我写过的课程:

class map
{
private:
  struct FIELD
  {
    string key;
    TYPE value;
  };
  vector<FIELD> data;
public:
  TYPE& operator[] (const string index)
  {
    typename vector<FIELD>::iterator idx;
    for(idx = data.begin(); idx != data.end(); ++idx)
    {
      if(idx->key == index)     return idx->value;
    }
    if(idx == data.end())
    {
      FIELD toAdd;
      toAdd.key = index;
      data.push_back(toAdd);
    }
    for(idx = data.begin(); idx != data.end(); ++idx)
    {
      if(idx->key == index) return idx->value;
    }
    return idx->value;
  }
};

它只适用于像 `iv["john"] = 23; 这样的赋值操作 但是当我尝试读取未初始化的元素时, operator[] 创建仅包含键的新元素,这是错误的。我知道没有像检查值是否未初始化这样的事情。问题是写入和读取操作都调用 operator[] ,我不太明白在这种情况下如何抛出异常。 我浏览了整个网络,发现我可以创建两个索引运算符,一个用于读取,一个用于写入 - 像这样:

TYPE& operator[] (const string index)
TYPE operator[] (const stirng index) const;

编译器会知道什么时候使用哪个。但我想这根本解决不了问题。

【问题讨论】:

  • std::map中,他们已经做到了operator[]总是使用默认构造的T自动创建新元素,而at是一个会抛出异常的元素,如果它不在那里。
  • 是的,我知道,但是如何在索引为 stl::string 的 stl::vector 上实现 at() 功能?
  • 只需将throw 放在if(idx == data.end()) 中,而不是添加一个新的。
  • 您在这里没有太多选择。要么 (1) 没有返回引用的 operator[],要么 (2) 模仿 std::map 行为,要么 (3) 每当找不到键时抛出异常。 at() 从不向向量添加新项目,因此您可以使用选项 3 轻松复制此行为。
  • 标准命名空间是std,而不是stl(这是一个很好的理由,STL 与它完全无关)

标签: c++ exception vector map operator-keyword


【解决方案1】:

不要尝试重新实现std::map,而是为其创建一个别名:

template<class Type>
using map = std::map<std::string, Type>;

记住不要导入using namespace std;,因为it is considered 不好的做法在这种情况下你会遇到名称冲突。

是的,std::map::operator[] 总是在地图内创建一个元素。如果元素不存在,您可以使用std::map::at 使其抛出异常std::out_of_range,或使用map.find(key) == map.end() 进行检查。

你的主要会变成:

int main() {
    map<int> iv;
    iv["john"] = 23;

    int ia = iv["john"]++;
    int ib = iv["john"];

    std::cout << ia << " " << ib << std::endl; // prints 23 24
    try {
        int ic = iv.at("jack");
        //         ^^^^      ^
    } catch(const std::out_of_range&) {
    //      ^^^^^^^^^^^^^^^^^^^^^^^^
        std::cout << "Uninitialized map element!" << std::endl;
    };
}

【讨论】:

  • 好吧,这将是更好的方法,但我不允许更改主程序,并且必须在不同的 std 容器上构建和模仿 std::map 的行为。我想出了一个想法,我可以创建两个索引运算符,一个用于读取,一个用于写入,然后用于写入的一个将像现在一样工作,一个用于读取的将检查索引(字符串)是否存在并且如果不是 - 抛出和异常。为此,我还发现在这种情况下我应该创建一个帮助类来区分阅读和写作。但我不太清楚如何在我的示例中实现它
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-29
  • 1970-01-01
相关资源
最近更新 更多