【问题标题】:How to make an iterator to a read-only object writable (in C++)如何使只读对象的迭代器可写(在 C++ 中)
【发布时间】:2013-05-03 08:58:56
【问题描述】:

我创建了我自己类型的unordered_set struct。我有一个 iterator 到这个集合,并且想增加 iterator 指向的 struct 的成员 (count)。但是,编译器会抱怨以下消息:

main.cpp:61:18: error: increment of member ‘SentimentWord::count’ in read-only object

我该如何解决这个问题?

这是我的代码:

#include <fstream>
#include <iostream>
#include <cstdlib> 
#include <string>
#include <unordered_set>


using namespace std;


struct SentimentWord {
  string word;
  int count;
};


//hash function and equality definition - needed to used unordered_set with type   SentimentWord
struct SentimentWordHash {
  size_t operator () (const SentimentWord &sw) const;
};

bool operator == (SentimentWord const &lhs, SentimentWord const &rhs);



int main(int argc, char **argv){


  ifstream fin;
  int totalWords = 0;
  unordered_set<SentimentWord, SentimentWordHash> positiveWords;
  unordered_set<SentimentWord, SentimentWordHash> negativeWords;


  //needed for reading in sentiment words
  string line;
  SentimentWord temp;
  temp.count = 0;


  fin.open("positive_words.txt");
  while(!fin.eof()){
    getline(fin, line);
    temp.word = line;
    positiveWords.insert(temp);
  }
  fin.close();


  //needed for reading in input file
  unordered_set<SentimentWord, SentimentWordHash>::iterator iter;


  fin.open("041.html");
  while(!fin.eof()){
    totalWords++;
    fin >> line;
    temp.word = line;
    iter = positiveWords.find(temp);
    if(iter != positiveWords.end()){
      iter->count++;
    }
  }


  for(iter = positiveWords.begin(); iter != positiveWords.end(); ++iter){
    if(iter->count != 0){
      cout << iter->word << endl;
    }
  }


  return 0;

}


size_t SentimentWordHash::operator () (const SentimentWord &sw) const {
  return hash<string>()(sw.word);
}


bool operator == (SentimentWord const &lhs, SentimentWord const &rhs){
  if(lhs.word.compare(rhs.word) == 0){
    return true;
  }
  return false;
} 

非常感谢任何帮助!

【问题讨论】:

标签: c++ pointers iterator


【解决方案1】:

unordered_set 中的元素是,by definition,不可变:

在 unordered_set 中,一个元素的值同时是它的 键,唯一标识它。密钥是不可变的,因此, unordered_set 中的元素不能在容器中修改一次 - 不过,它们可以插入和移除。

我会投票让你改用unordered_map,使用字符串作为键,使用 int 作为映射值。

【讨论】:

    【解决方案2】:

    一个解决方案(但一个肮脏的黑客)是让你的计数器可变,这意味着你允许即使在 const 对象上也可以改变它。

    struct SentimentWord {
      string word;
      mutable int count;
    };
    

    正如我已经说过的,这是一个肮脏的 hack,因为它允许您违反规则(您可以软化它们)。规则是有原因的。我什至不确定这是否可行,因为unordered_set 的定义说一旦插入就不能修改值,这也是有原因的。

    更好的解决方案是使用 ma​​p,它使用单词作为键,计数器作为值。然后,您的代码不必使用find,而只需使用直接返回引用(而不是迭代器)的下标运算符(“数组访问”运算符)访问元素。在这个引用上,使用增量运算符,如下所示:

    std::unordered_map<std::string,int> positiveWords;
    //...
    positiveWords[word]++;
    

    那么你根本不需要你的结构,当然也不需要你的自定义比较运算符重载。


    技巧(以备不时之需):如果您想按其值对地图进行排序(如果您需要一个统计地图,其中最常见的词排在第一位),请使用第二个(但已排序的)带有反转键的地图和价值。这将按原始值对其进行排序,该值现在是键。以相反的顺序迭代它以从最常用的单词开始(或使用std::greater&lt;int&gt; 作为比较运算符构造它,作为第三个模板参数提供)。

    【讨论】:

      【解决方案3】:

      std::unordered_set 很不高兴,因为它担心您会以与另一个对象相同的方式更改对象,这会违反集合。 ISTM 你真的想要一个从stringintmap(根本不是一个集合),并且迭代器会让你更改返回的,如果不是关键。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-12
        • 2019-12-03
        • 2012-04-27
        • 2018-06-06
        相关资源
        最近更新 更多