4

我仍然是新stl成员的新手。谁能指出为什么这段代码会出现分段错误?

#include<memory>
#include<stdio.h>
#include<map>
#include<set>
#include<string>
using namespace std;
struct StubClass
{
    weak_ptr<string> b;
    int c;
    friend bool operator==(StubClass x,StubClass y);
    friend bool operator<(StubClass x,StubClass y);
    StubClass(weak_ptr<string> x):b(x){c=5;}    
};
bool operator==(StubClass d,StubClass c) { return d.b==c.b;}
bool operator<(StubClass d,StubClass c) { return d.b<c.b; }


int main()
{
    shared_ptr<string> spPtr(new string("Hello"));
    weak_ptr<string> wpPtr(spPtr);
    StubClass hello(wpPtr);
    set<StubClass> helloSet;
    helloSet.insert(hello);
    if(helloSet.find(StubClass(wpPtr))!=helloSet.end()) printf("YAYA");
    else puts("Bye");
}

错误在行

if(helloSet.find(StubClass(wpPtr))!=helloSet.end()) printf("YAYA");

更多研究表明,调用 StubClass 的比较器函数时存在问题。我在这里编译程序

编辑:

bool operator==(StubClass d,StubClass c) { return d.b.lock()==c.b.lock();}
bool operator<(StubClass d,StubClass c) { return d.b.lock()<c.b.lock(); }

这解决了这个问题。我应该阅读更多内容。:(无论如何,社区中的任何人都可以解释第一个代码给出 SIGSEGV 的原因。我最终想通了,但仍然是一个很好的解释不会受到伤害。:)

4

2 回答 2

5

您的原始代码段错误,因为您不小心设置了无限递归:

bool operator<(StubClass d,StubClass c) { return d.b<c.b; }

没有operator<for weak_ptr。但是,您确实有从weak_ptrto的隐式转换StubClass。并且StubClass有一个operator<. 所以这个函数无限期地调用自己:因此是段错误。

inkooboo 目前接受的答案也将导致未定义的行为,可能导致崩溃。由于weak_ptrs在程序执行期间过期(比您的测试用例涉及更多的事情),那么它们的顺序将会改变。当这发生在 中的两个之间weak_ptrssetset将被损坏,可能导致崩溃。但是,有一种owner_less专门为此用例设计的使用方法:

bool operator==(const StubClass& d, const StubClass& c)
{
    return !owner_less<weak_ptr<string>>()(d.b, c.b) &&
           !owner_less<weak_ptr<string>>()(c.b, d.b);
}
bool operator<(const StubClass& d, const StubClass& c)
{
    return owner_less<weak_ptr<string>>()(d.b, c.b);
}

或者,如果您愿意,也可以使用成员函数对其进行编码owner_before。两者是等价的:

bool operator==(const StubClass& d, const StubClass& c)
{
    return !d.b.owner_before(c.b) && !c.b.owner_before(d.b);
}
bool operator<(const StubClass& d, const StubClass& c)
{
    return d.b.owner_before(c.b);
}

使用这些函数,即使一个weak_ptr过期而另一个没有过期,它们的排序仍然保持稳定。因此,您将拥有一个定义明确的set.

于 2012-06-14T15:27:20.943 回答
4

如果要比较存储在 weak_ptr 中的字符串,请执行以下操作:

bool operator<(StubClass d, StubClass c) 
{
    std::shared_ptr<std::string> a = d.b.lock();
    std::shared_ptr<std::string> b = c.b.lock();

    if (!a && !b)
        return false; 

    if (!a)
        return true;

    if (!b)
        return false;

    return *a < *b;
}

运行结果

于 2012-06-14T14:07:22.787 回答