我有一个简单的SequencesRange
类,可以迭代固定大小的随机基因组序列。
当我尝试用 连接所有序列的字符时std::views::join
,它工作得很好,但当我尝试用 进行管道传输时std::views::enumerate
,我得到了垃圾输出。我可以检查 valgrind 不太高兴,并产生了一些可怕的Conditional jump or move depends on uninitialised value(s)
#include <string>
#include <iostream>
#include <ranges>
class SequencesRange
{
public:
struct iterator
{
using iterator_category = std::forward_iterator_tag;
using value_type = std::string;
using difference_type = long;
using pointer = value_type*;
using reference = value_type const&;
iterator (size_t size, size_t nbItems) : value_(size,' '), nbItems_(nbItems)
{
next();
}
iterator() = default;
iterator(iterator const&) = default;
iterator(iterator && ) = default;
iterator& operator= (iterator const&) = default;
iterator& operator= (iterator &&) = default;
bool operator!= (const iterator& other) const { return nbItems_ != other.nbItems_; }
bool operator== (const iterator& other) const { return nbItems_ == other.nbItems_; }
iterator& operator++ () { next(); ++nbItems_; return *this; }
iterator operator++(int) { iterator tmp = *this; ++(*this); return tmp; }
reference operator* () const { return value_; }
value_type value_;
size_t nbItems_ = 0;
void next()
{
static std::array<char,4> letters = {'A','C','G','T'};
for (auto& c : value_) { c = letters[rand()%letters.size()]; }
}
};
public:
iterator begin() const { return iterator(size, 0); }
iterator end () const { return iterator(size, nbItems); }
size_t nbItems = 0;
size_t size = 0;
};
int main (int argc, char** argv)
{
SequencesRange iterable {1, 10}; // one sequence of length 10
for (auto [i,nt] : iterable | std::views::join | std::views::enumerate)
{
std::cout << nt; // got some garbage output here
}
// Note that the following is ok:
// for (auto nt : iterable | std::views::join) { std::cout << nt; }
}
这听起来像是糟糕的对象生命周期管理,我怀疑我的迭代器结构中存在一些愚蠢的东西,但我目前不知道在哪里。
奇怪的是:如果我用长度> = 16的序列配置迭代器,则不会出现任何错误。也许是短字符串优化的副作用?
更新:
iterator
请注意,对于使用整数标记的简化版本的结构,我没有异议end
:
更新:
如果我强制迭代器提供副本(即value_type operator* () const { return value_; }
),它就会起作用。
但我不明白为什么需要副本,iterable | std::views::join | std::views::enumerate
尽管只能使用引用iterable | std::views::join
。