I am still a novice in the new stl members.Can anyone point out why this code is giving segmentation fault?
#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");
}
The error is in line
if(helloSet.find(StubClass(wpPtr))!=helloSet.end()) printf("YAYA");
More research reveals there is a problem when the StubClass's comparator function is called. I am compiling the program here
EDIT:
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(); }
This resolved the issue.I should be reading more.:( Anyways can anyone from the community explain the reason why the first code gives SIGSEGV.I figured it out eventually,but still a nice explanation won't hurt. :)
Your original code segfaults because you've accidentally set up an infinite recursion:
bool operator<(StubClass d,StubClass c) { return d.b<c.b; }
There is no operator<
for weak_ptr
. However you do have an implicit conversion from weak_ptr
to StubClass
. And StubClass
has an operator<
. So this function calls itself indefinitely: thus the segfault.
The currently accepted answer from inkooboo will also lead to undefined behavior, probably resulting in a crash. As weak_ptrs
become expired during the execution of your program (something more involved than your test case), then the ordering of them will change. When this happens between two weak_ptrs
in the set
, the set
will become corrupted, likely leading to a crash. However there is a way around this using owner_less
which was designed specifically for this use case:
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);
}
Or, if you prefer, this can also be coded using the member function owner_before
. Both are equivalent:
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);
}
Using these functions, even when one weak_ptr
expires and the other doesn't, their ordering remains stable. And thus you'll have a well-defined set
.
If you want to compare strings stored in weak_ptr do this:
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;
}
Run result
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With