gpt4 book ai didi

c++ - 在自定义迭代器上应用 reverse_iterator 后引用失效

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:21:16 25 4
gpt4 key购买 nike

我实现了一个双向迭代器,但它不是对数据结构进行操作,而是返回一个可以在两个方向上迭代计算的数学序列。事实上,我正在迭代整数,使用++ 和 -- 在 int 上。这意味着数据不会存储在不同的结构中,因此当迭代器超出范围时,值也会超出范围。

尽管如此,我希望下一个代码(最小失败示例)示例能够工作,因为迭代器始终保持在范围内。但它不起作用:(

#include <iostream>
#include <iterator>
#include <vector>

class my_iterator : public std::iterator<std::bidirectional_iterator_tag, int> {
int d_val = 12;
public:
my_iterator operator--(int) { std::cout << "decrement--\n"; return my_iterator(); }
my_iterator &operator--() { std::cout << "--decrement\n"; return *this; }
my_iterator operator++(int) { std::cout << "increment++\n"; return my_iterator(); }
my_iterator &operator++() { std::cout << "++increment\n"; return *this; }

int &operator*() { std::cout << "*dereference\n"; return d_val; }

bool operator==(my_iterator const &o) { return false; }
bool operator!=(my_iterator const &o) { return true ; }
};


int main() {
auto it = std::reverse_iterator<my_iterator>();
int &i = *it;
if (true)
{
std::cout << i << '\n';
}
else
{
std::vector<int> vec;
vec.push_back(i);
std::cout << vec[0] << '\n';
}
}

来源:http://ideone.com/YJKvpl

if 分支导致内存违规,正如 valgrind 正确检测到的那样:

--decrement
*dereference
==7914== Use of uninitialised value of size 8
==7914== at 0x4EC15C3: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914== by 0x4EC16FB: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914== by 0x4EC1C7C: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914== by 0x4ECEFB9: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914== by 0x40087B: main (divine.cc:25)
==7914==
==7914== Conditional jump or move depends on uninitialised value(s)
==7914== at 0x4EC15CF: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914== by 0x4EC16FB: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914== by 0x4EC1C7C: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914== by 0x4ECEFB9: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914== by 0x40087B: main (divine.cc:25)
==7914==
==7914== Conditional jump or move depends on uninitialised value(s)
==7914== at 0x4EC1724: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914== by 0x4EC1C7C: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914== by 0x4ECEFB9: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914== by 0x40087B: main (divine.cc:25)
==7914==
12
==7914==
==7914== HEAP SUMMARY:
==7914== in use at exit: 0 bytes in 0 blocks
==7914== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==7914==
==7914== All heap blocks were freed -- no leaks are possible
==7914==
==7914== For counts of detected and suppressed errors, rerun with: -v
==7914== Use --track-origins=yes to see where uninitialised values come from
==7914== ERROR SUMMARY: 5 errors from 3 contexts (suppressed: 0 from 0)

else 分支不会导致内存违规,或者至少在我的 valgrind 可以检测到的范围内。但是, vector 中存储的值是“随机的”:

--decrement
*dereference
-16777520

我对发生的事情感到有点惊讶。迭代器应该一直在范围内,但引用似乎失效了。为什么在打印 12 时会出现内存冲突,或者在存储不同于 12 的内容时为什么没有出现内存冲突?

最佳答案

reverse_iterator 不适用于所谓的“隐藏迭代器”,即返回对自身内部事物的引用的迭代器。 reverse_iteratoroperator* 制作包装迭代器的拷贝,递减它,并返回取消引用拷贝的结果。因此,如果取消引用的迭代器返回对自身内部某物的引用,则该引用将变为悬空。

在 C++11 规范中尝试让它工作,但事实证明,如果不为非隐藏迭代器增加大量开销* 就不可能实现,所以 the specification was reverted to the C++03 version .


* 为了支持“隐藏迭代器”,必须添加一个额外的数据成员来存储递减后的当前迭代器,将reverse_iterator 的大小加倍;然后必须使用某种形式的同步,因为 operator *const - 因此必须同时从多个线程调用而不会导致数据竞争 - 但必须修改此附加数据成员。对于这种不常见的用例,向所有 reverse_iterator 添加大量开销。

关于c++ - 在自定义迭代器上应用 reverse_iterator 后引用失效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28595084/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com