草庐IT

C++ 随机访问迭代器超出范围

coder 2024-02-22 原文

为了同时对两个范围进行分区或排序(与 std::partitionstd::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;
}

使用此代码会在分区期间产生异常抛出:读取访问冲突。使用 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::partition 调用中有未定义的行为:

return std::partition(&first, &last, p)->it1;

这会导致对 DualRandIt<> 类型的元素范围进行分区两个地址之间&first&last .你想要的是:

return std::partition(first, last, p).it1;

但是您不再对指针进行分区,而是对迭代器进行分区,这会导致很多错误,因为您的迭代器不符合标准。

要了解如何编写迭代器,请参见此处:How to implement an STL-style iterator and avoid common pitfalls?

关于C++ 随机访问迭代器超出范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37840879/

有关C++ 随机访问迭代器超出范围的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  4. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  5. ruby - 触发器 ruby​​ 中 3 点范围运算符和 2 点范围运算符的区别 - 2

    请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是

  6. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

    我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

  7. ruby - 当使用::指定模块时,为什么 Ruby 不在更高范围内查找类? - 2

    我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or

  8. ruby - 为什么 Ruby 的 each 迭代器先执行? - 2

    我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试

  9. Ruby 从大范围中获取第 n 个项目 - 2

    假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit

  10. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

随机推荐