【问题标题】:C++ - Overloading of operators needed for an iteratorC++ - 重载迭代器所需的运算符
【发布时间】:2022-01-10 15:09:16
【问题描述】:

我正在尝试在允许读取特定文件格式的库上创建迭代器。

从文档中,要读取文件内容,您需要执行以下操作:

CKMCFile database;

if (!database.OpenForListing(path)) {
  std::cerr << "ERROR: unable to open " << path << std::endl;
}

CKMCFileInfo info;
database.Info(info);

CKmerAPI kmer(info.kmer_length);

uint32 cnt;
std::vector<uint64_t> data;
std::vector<uint64> ulong_kmer;
data.reserve(info.total_kmers);

while (database.ReadNextKmer(kmer, cnt)) {
  kmer.to_long(ulong_kmer);
  data.push_back(ulong_kmer[0]);
}

现在,我从这门课开始wrapper

class FileWrapper {
  CKMCFile database;
  CKMCFileInfo info;
  Iterator _end;

  public:
    explicit FileWrapper(const std::string &path) {
      if (!database.OpenForListing(path)) {
        std::cout << "ERROR: unable to open " << path << std::endl;
      }

      database.Info(info);
    }

    Iterator begin() {
      Iterator it;
      it.database = &database;
      it.total = 0;

      uint32_t cnt;
      std::vector<uint64_t> ulong_kmer;

      CKmerAPI tmp(info.kmer_length);
      database.ReadNextKmer(tmp, cnt);
      tmp.to_long(ulong_kmer);

      return it;
    }
    
    Iterator end() const { return _end; }
    uint64_t size() { return info.total_kmers; }
};

然后,这是Iterator 类:

class Iterator {
    friend class FileWrapper;

    CKMCFileInfo info;
    CKMCFile *database;
    uint64_t kmer, total;
    
    public:
      Iterator &operator++() {
        ++total;

        uint32_t cnt;
        std::vector<uint64_t> ulong_kmer;

        CKmerAPI tmp(info.kmer_length);
        database->ReadNextKmer(tmp, cnt);
        tmp.to_long(ulong_kmer);

        return *this;
      }

      bool operator<(const Iterator &rhs) const { return total < rhs.total; }
      uint64_t operator*() const { return kmer; }
  };

但是,在某些测试中,我不能将for loop 用于for (auto it = begin(); it != end(); ++i) { ... }begin() + size() 之类的东西。我怎样才能正确地超载这两个操作员? opeartor!=operato+

【问题讨论】:

  • 您可能会遇到更严重的构建错误问题:您忘记初始化total,这将导致您在使用它时出现未定义的行为
  • @Someprogrammerdude 一个编译时间,现在我有这个错误:error: no match for 'operator!='

标签: c++ iterator c++17 operator-overloading overloading


【解决方案1】:

在此之前你必须考虑两件主要的事情:

  1. 所有权。目前,您必须确保您的FileWrapper 至少与通过调用begin() 从它返回的任何Iterator 一样长(因为您的Iterators 存储指向FileWrapper 对象拥有的数据的指针)。如果不能保证,不妨考虑使用unique_ptrs 或shared_ptrs
  2. 迭代器类别。正如 cmets 中所讨论的,您的数据库似乎要求您使用“input iterators”。它们只能加一(不提供operator+(int))并取消引用。事实上,迭代器begin() + 10 会是什么样子?如果这应该推进您的文件指针,那么您不能将结尾定义为 begin() + size(),因为那样只会跳过文件。
  3. 表示。终结迭代器应该是什么样的?一个简单的选择可能是用database == nullptr 表示结尾。在这种情况下,operator!= 可能如下所示:
bool is_end() const { return database == nullptr; }

bool operator==(const Iterator& other) const {
  if(is_end()) return other.is_end();
  if(other.is_end()) return false;
  return (database == other.database) && (total == other.total);
}

bool operator!=(const Iterator& other) const { return !operator==(other); }

现在,您需要确保所有终端迭代器都具有database == nullptr 的代码,并且每当非终端迭代器通过应用operator++() 变为终端迭代器时,您需要设置database = nullptrtotal = 0(或其他东西)。

最后的注释:您的Iterators 在构造之后和分配database 成员之前可能处于不一致的状态。为 Iterator 声明一个适当的构造函数来初始化其成员是谨慎的。

编辑:here 的集成建议

【讨论】:

  • operator+ 我该如何定义呢?我不需要 end() 迭代器,end() = first() + size()
  • 这取决于你想如何使用它。当您简单地将operator+=(size_t x) 定义为调用operator++ x 次时,您的文件指针将前进,并且任何其他迭代器(或先前创建的该迭代器的副本)都将关闭。所以,确实,对于文件数据,我总是只使用 ForwardIterators(即只提供 ++,但不提供 +),而不是 RandomAccess 迭代器(提供 +++
  • @th3g3ntl3man:您正在制作一个纯输入迭代器。你不应该给它operator+
  • @igel:由于数据库对象似乎内部存储了位置,所以它不能是 ForwardIterator(前向迭代器必须提供多遍,而这不是在这里似乎可行)。
  • 该库仅支持forward_iterator。对我来说最好的事情是只能使用 begin() 插入器和文件的总元素 (total_kmers) 扫描文件。我如何使用与您的代码集成的代码来做到这一点?
猜你喜欢
  • 2020-06-14
  • 2021-07-09
  • 2011-10-18
  • 1970-01-01
  • 2011-12-07
  • 2013-09-07
  • 2017-02-22
  • 2012-03-12
  • 1970-01-01
相关资源
最近更新 更多