【问题标题】:segmentation fault because of comparison function由于比较功能导致的分段错误
【发布时间】:2016-03-30 12:34:27
【问题描述】:

我尝试在 spoj 上解决这个问题。 http://www.spoj.com/problems/BUSYMAN/

虽然我能够解决它,但我遇到了一个非常奇怪的错误。我试图了解它的原因,但失败了。我有两个代码。

/////////////////////////////////////// ////

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

class activity
{
    public:
    int start,end;
};

bool comp(activity p, activity q)
{
    if(p.end<q.end)return true;
    if(p.end==q.end&&p.start<=q.start)return true;
    return false;
}

int main()
{
    int t;
    cin>>t;
    vector<activity> v;
    for(int i=0;i<t;i++)
    {
        int n;
        cin>>n;

        v.resize(n);
        for(int j=0;j<n;j++)cin>>v[j].start>>v[j].end;
        sort(v.begin(),v.end(),comp);
        int ans=0,currend=0;
        for(int j=0;j<n;j++)
        {
            if(v[j].start>=currend){ans++;currend=v[j].end;
        }

    }
    cout<<ans<<endl;
    }
}

/////////////////////////////////////// p>

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

class activity
{
    public:
    int start,end;
};

bool comp(activity p, activity q)
{
    if(p.end<q.end)return true;
    if(p.end==q.end&&p.start>=q.start)return true;
    return false;
}

int main()
{
    int t;
    cin>>t;
    int n;
    vector<activity> v;
    for(int i=0;i<t;i++)
    {
        cin>>n;
        v.resize(n);
        for(int j=0;j<n;j++)
            cin>>v[j].start>>v[j].end;
        sort(v.begin(),v.end(),comp);
        int ans=0,currend=0;
        for(int j=0;j<n;j++)
        {
            if(v[j].start>=currend)
            {
                ans++;currend=v[j].end;
            }
        }
        cout<<ans<<endl;
    }
}

//////////////////////////

我的问题是第一个在 spoj 上给出了分段错误,而第二个没有。两者之间的唯一区别是比较功能。我只是碰巧以两种相似的方式定义了比较函数的第二条语句。但它在第一种情况下给了我分段错误,但在第二种情况下没有。

在此处输入图像描述

在上面的两个图像中,有两个代码具有各自的提交 ID,在第三个中,它显示了一个段错误,而另一个则没有。您也可以使用我的 spoj 个人资料上的提交 ID 进行验证。

【问题讨论】:

    标签: c++ segmentation-fault


    【解决方案1】:

    因为bool comp(activity p, activity q) 不符合Compare 的要求,请参阅std::sort

    应该是这样的:

    bool comp(const activity& p, const activity& q)
    {
        return p.end < q.end || (p.end ==q.end && p.start < q.start);
    }
    

    或

    struct comp {
        bool operator()(const activity& p, const activity& q) const
        {
            return p.end < q.end || (p.end ==q.end && p.start < q.start);
        }
    };
    

    或

    struct comp {
        bool operator()(const activity& p, const activity& q) const
        {
            return std::tie(p.end, p.start) < std::tie(q.end, q.start);
        }
    };
    

    【讨论】:

    • 但它适用于第二种情况。除了第二行中的比较运算符外,这与第一种情况类似。我已经以类似的方式使用它很长时间了,它总是有效的。除了函数第二行中的比较运算符外,一切都相同,但一个有效,另一个无效。你能告诉为什么它在第二种情况下有效。
    • 对我来说,你的两个都可以正常工作。如果Compare 没有对值进行严格的弱排序,则标准不会说明该行为。
    • @M.M 你能指出标准中的哪个语句说它是未定义的行为吗?
    • 你试过 spoj.在我的电脑上它工作正常,但只在 spoj 上给出分段错误。在我的电脑上,他们都给出了正确的答案。但是一个在 spoj 上给出了分段错误,而另一个没有。
    • @AkashGarg 不,我没有。但是,如果比较器是严格的弱排序,std::sort 应该可以正常工作
    【解决方案2】:

    C++ 的规则是std::sort 的比较器必须给出strict weak ordering。

    因此,对于相等的元素,比较器必须返回 false。但是这个测试:

    if(p.end<q.end)return true;
    if(p.end==q.end&&p.start<=q.start)return true;
    return false;
    

    如果元素相等则返回true,因此这是一个无效的比较器。

    在您的第二次尝试中:

    if(p.end<q.end)return true;
    if(p.end==q.end&&p.start>=q.start)return true;
    return false;
    

    这有同样的问题,也会导致未定义的行为。

    当代码具有未定义的行为时,您无法从观察到的行为中推断出任何东西,您得到什么行为只是机会(可能取决于有关编译器特定排序算法选择的一些细节)。

    在第一个比较器中将 &lt;= 更改为 &lt; 将产生一个有效的比较器,其排序顺序为结束和开始升序。

    【讨论】:

    • 我过去曾看到编译器在比较器无效时发出警告,但现在找不到任何相关信息
    • 但第二次尝试有效。这就是我要的解释。为什么第二个工作。如果它们都不起作用,那么显然我不会要求它。我会直接进行严格的弱排序。
    • @AkashGarg 当undefined behaviour 发生时,任何事情都可能发生
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-09
    • 2018-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多