C++随机访问迭代器超出范围
C++ Random Access Iterator out of range
为了同时对两个范围进行分区或排序(而不是只对一个范围进行std::partition
或std::sort
),同时在比较过程中只考虑第一个范围的元素,我创建了一个模板随机访问迭代器DualRandIt
包装两个随机访问迭代器。
#include <algorithm>
// Random Access Iterator wrapping two Random Access Iterators
template<typename RandIt1, typename RandIt2>
struct DualRandIt {
using difference_type = typename std::iterator<std::random_access_iterator_tag, DualRandIt<RandIt1, RandIt2> >::difference_type;
DualRandIt(RandIt1 it1, RandIt2 it2) : it1(it1), it2(it2) {}
DualRandIt(const DualRandIt<RandIt1, RandIt2> &v) : it1(v.it1), it2(v.it2) {}
inline DualRandIt<RandIt1, RandIt2> &operator=(const DualRandIt<RandIt1, RandIt2> &v) {
it1 = v.it1;
it2 = v.it2;
return *this;
}
inline DualRandIt<RandIt1, RandIt2> &operator+=(difference_type n) {
it1 += n;
it2 += n;
return (*this)
}
inline DualRandIt<RandIt1, RandIt2> operator+(difference_type n) const {
return DualRandIt<RandIt1, RandIt2>(it1 + n, it2 + n);
}
friend inline DualRandIt<RandIt1, RandIt2> operator+(difference_type n, const DualRandIt<RandIt1, RandIt2> &v) {
return v + n;
}
inline DualRandIt<RandIt1, RandIt2> &operator-=(difference_type n) {
it1 -= n;
it2 -= n;
return (*this)
}
inline DualRandIt<RandIt1, RandIt2> operator-(difference_type n) const {
return DualRandIt<RandIt1, RandIt2>(it1 - n, it2 - n);
}
inline difference_type operator-(const DualRandIt<RandIt1, RandIt2> &v) const {
return it1 - v.it1; // or it2 - v.it2;
}
friend inline void swap(DualRandIt<RandIt1, RandIt2> &v1, DualRandIt<RandIt1, RandIt2> &v2) {
std::swap(v1.it1, v2.it1);
std::swap(v1.it2, v2.it2);
}
inline DualRandIt<RandIt1, RandIt2> operator[](difference_type i) const {
return DualRandIt<RandIt1, RandIt2>(it1[i], it2[i]);
}
inline bool operator==(const DualRandIt<RandIt1, RandIt2> &v) const {
return it1 == v.it1;
}
inline bool operator!=(const DualRandIt<RandIt1, RandIt2> &v) const {
return it1 != v.it1;
}
inline bool operator<(const DualRandIt<RandIt1, RandIt2> &v) const {
return it1 < v.it1;
}
inline bool operator<=(const DualRandIt<RandIt1, RandIt2> &v) const {
return it1 <= v.it1;
}
inline bool operator>(const DualRandIt<RandIt1, RandIt2> &v) const {
return it1 > v.it1;
}
inline bool operator>=(const DualRandIt<RandIt1, RandIt2> &v) const {
return it1 >= v.it1;
}
RandIt1 it1;
RandIt2 it2;
};
// Simultaneous partitioning of two ranges with a predicate (only applied to elements of the first range)
template<typename BidirIt1, typename BidirIt2, typename UnaryPredicate>
inline BidirIt1 dual_partition(BidirIt1 f1, BidirIt1 l1, BidirIt2 f2, BidirIt2 l2, UnaryPredicate p) {
DualRandIt<BidirIt1, BidirIt2> first(f1, f2);
DualRandIt<BidirIt1, BidirIt2> last(l1, l2);
return std::partition(&first, &last, p)->it1;
}
使用此代码可在分区期间提供Exception thrown: read access violation
。使用std::partition
在第一个范围内工作正常,并且由于逻辑运算符重载的实现似乎相当微不足道,我想知道如何超出范围?
以下代码可用于触发异常:
// --------------------------------------------------------
// For testing purposes
// --------------------------------------------------------
struct Compare {
Compare(int position) : position(position) {}
inline bool operator()(const int &info) const {
return info <= position;
}
inline bool operator()(const DualRandIt<int*, int*> &info) const {
return *info.it1 <= position;
}
const int position;
};
int main() {
int a[5];
int b[5];
for (int i = 0; i < 5; ++i) {
a[i] = 5 - i;
b[i] = 5 - i;
}
//std::partition(&a[0], &a[4] + 1, Compare(3));
dual_partition(&a[0], &a[4]+1, &b[0], &b[4] + 1, Compare(3));
}
编辑版本 2:
#include <algorithm>
template<typename Element1, typename Element2>
struct DualRandIt {
DualRandIt(Element1 *it1, Element2 *it2) : it1(it1), it2(it2) {}
DualRandIt(const DualRandIt<Element1, Element2> &v) : it1(v.it1), it2(v.it2) {}
inline DualRandIt<Element1, Element2> &operator=(const DualRandIt<Element1, Element2> &v) {
it1 = v.it1; it2 = v.it2;
return *this;
}
typedef std::ptrdiff_t difference_type;
inline DualRandIt<Element1, Element2> &operator++() {
++it1; ++it2;
return (*this);
}
inline DualRandIt<Element1, Element2> operator++(int) {
DualRandIt<Element1, Element2> it = *this;
++it1; ++it2;
return it;
}
inline DualRandIt<Element1, Element2> operator+(difference_type n) const {
return DualRandIt<Element1, Element2>(it1 + n, it2 + n);
}
inline DualRandIt<Element1, Element2> &operator+=(difference_type n) {
it1 += n; it2 += n;
return (*this)
}
friend inline DualRandIt<Element1, Element2> operator+(difference_type n, const DualRandIt<Element1, Element2> &v) {
return v + n;
}
inline DualRandIt<Element1, Element2> &operator--() {
--it1; --it2;
return (*this);
}
inline DualRandIt<Element1, Element2> operator--(int) {
DualRandIt<Element1, Element2> it = *this;
--it1; --it2;
return it;
}
inline DualRandIt<Element1, Element2> operator-(difference_type n) const {
return DualRandIt<Element1, Element2>(it1 - n, it2 - n);
}
inline DualRandIt<Element1, Element2> &operator-=(difference_type n) {
it1 -= n; it2 -= n;
return (*this)
}
inline difference_type operator-(const DualRandIt<Element1, Element2> &v) const {
return it1 - v.it1; // or it2 - v.it2;
}
inline DualRandIt<Element1, Element2> operator[](difference_type i) const {
return DualRandIt<Element1, Element2>(it1[i], it2[i]);
}
struct value_type {
inline bool operator<(const Element1 &e) const {
return e1 < e;
}
inline bool operator<(const value_type &v) const {
return e1 < v.e1;
}
Element1 e1;
Element2 e2;
};
struct reference {
inline reference &operator=(const reference &v) {
*e1 = *v.e1; *e2 = *v.e2;
return *this;
}
inline reference &operator=(const value_type &v) {
*e1 = v.e1; *e2 = v.e2;
return *this;
}
operator value_type() const {
value_type rv = { *e1, *e2 };
return rv;
}
inline bool operator==(const reference &v) const {
return *e1 == *v.e1;
}
inline bool operator!=(const reference &v) const {
return *e1 != *v.e1;
}
inline bool operator<(const reference &v) const {
return *e1 < *v.e1;
}
inline bool operator<=(const reference &v) const {
return *e1 <= *v.e1;
}
inline bool operator>(const reference &v) const {
return *e1 > *v.e1;
}
inline bool operator>=(const reference &v) const {
return *e1 >= *v.e1;
}
inline bool operator==(const Element1 &e) const {
return *e1 == e;
}
inline bool operator!=(const Element1 &e) const {
return *e1 != e;
}
inline bool operator<(const Element1 &e) const {
return *e1 < e;
}
inline bool operator<=(const Element1 &e) const {
return *e1 <= e;
}
inline bool operator>(const Element1 &e) const {
return *e1 > e;
}
inline bool operator>=(const Element1 &e) const {
return *e1 >= e;
}
inline bool operator==(const value_type &v) const {
return *e1 == v.e1;
}
inline bool operator!=(const value_type &v) const {
return *e1 != v.e1;
}
inline bool operator<(const value_type &v) const {
return *e1 < v.e1;
}
inline bool operator<=(const value_type &v) const {
return *e1 <= v.e1;
}
inline bool operator>(const value_type &v) const {
return *e1 > v.e1;
}
inline bool operator>=(const value_type &v) const {
return *e1 >= v.e1;
}
Element1 *e1;
Element2 *e2;
};
reference operator*() {
reference rv = { it1, it2 };
return rv;
}
typedef reference pointer;
inline bool operator==(const DualRandIt<Element1, Element2> &v) const {
return it1 == v.it1;
}
inline bool operator!=(const DualRandIt<Element1, Element2> &v) const {
return it1 != v.it1;
}
inline bool operator<(const DualRandIt<Element1, Element2> &v) const {
return it1 < v.it1;
}
inline bool operator<=(const DualRandIt<Element1, Element2> &v) const {
return it1 <= v.it1;
}
inline bool operator>(const DualRandIt<Element1, Element2> &v) const {
return it1 > v.it1;
}
inline bool operator>=(const DualRandIt<Element1, Element2> &v) const {
return it1 >= v.it1;
}
typedef std::random_access_iterator_tag iterator_category;
typedef reference pointer;
Element1 *it1;
Element2 *it2;
};
struct Compare {
Compare(int position) : position(position) {}
inline bool operator()(const DualRandIt<int, int>::reference &info) const { return info <= position; }
const int position;
};
int main() {
int a[] = { 5,4,3,2,1 };
int b[] = { 5,4,3,2,1 };
DualRandIt<int, int> first(&a[0], &b[0]);
DualRandIt<int, int> last(&a[5], &b[5]);
std::partition(first, last, Compare(3));
//std::sort(first, last);
}
排序现在可以工作,但分区似乎保留了中间元素之后的元素。此外,我不确定是否真的有必要将迭代器限制为DualRandIt
指针?
也可以重写分区方法等,将每个交换也应用于其他范围: 模板
template<typename BidirIt1, typename BidirIt2, typename UnaryPredicate>
BidirIt1 dual_partition(BidirIt1 f1, BidirIt1 l1, BidirIt2 f2, BidirIt2 l2, UnaryPredicate p) {
BidirIt1 fp = std::find_if_not(f1, l1, p);
f2 += (fp - f1);
f1 = fp;
if (f1 == l1) return f1;
BidirIt1 i = std::next(f1);
BidirIt2 j = std::next(f2);
for (; i != l1; ++i, ++j) {
if (p(*i)) {
std::iter_swap(i, f1);
std::iter_swap(j, f2);
++f1;
++f2;
}
}
return f1;
}
你在 std::p artition 调用中有未定义的行为:
return std::partition(&first, &last, p)->it1;
这会导致在两个地址&first
和&last
之间划分类型为DualRandIt<>
的元素范围。你在这里想要的是:
return std::partition(first, last, p).it1;
但是你不再分区指针而是迭代器,这将得到很多错误,因为你的迭代器不符合标准。
要了解如何编写迭代器,请参阅此处:如何实现 STL 风格的迭代器并避免常见的陷阱?
相关文章:
- 转到基于范围的 for 循环中的下一个迭代器
- C++:返回一个基于范围 for 循环迭代器,其中包含继承对象
- 迭代器范围的平衡分区,没有LegacyRandomAccessIterator
- 为什么范围算法与 std 的迭代器不兼容?
- Deque 迭代器超出范围
- unordered_set范围插入与迭代器
- 类型不可知的抽象以使用相同的运行时接口处理正向和反向迭代器和范围?
- 访问基于范围的循环(如for_each)中的std::map迭代器
- 迭代器的范围 TS 和 C++20 概念是否需要能够使用"运算符>"?
- 列出超出范围的擦除迭代器
- 如何使用提升范围将自定义迭代器封装在函数中
- 无法取消引用超出范围的向量迭代器 - 有什么问题?
- 如何在基于范围的 for 循环中更改(向前/向后移动)迭代器?
- 如何修复错误,迭代器未在此范围内声明,并且迭代器未命名类型'
- 将迭代器放置为临时范围时,非销钉 - 操作和错误
- C 迭代器范围使用指针到数组
- 为什么我们要把 :: (范围重新定位运算符)放在迭代器之前
- 将迭代器范围复制到矢量而不重复
- C++:指向错误元素的提升范围迭代器
- re C++范围迭代器:只有一个类不好吗