2012-06-14 72 views
4

我仍然是新stl成員中的新手。任何人都可以指出爲什麼此代碼給出了分段錯誤?weak_ptr中的比較運算符C++

#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"); 
} 

的錯誤是在管線

如果(helloSet.find(StubClass(wpPtr))= helloSet.end()!)的printf( 「YAYA」);

更多的研究表明,StubClass的比較函數被調用時會出現問題。 我編譯程序here

編輯:

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(); } 

這解決了issue.I應閱讀更加:( 不管怎麼說來自社區的任何人都可以解釋爲什麼第一代碼給出SIGSEGV的原因。我想通了最後,但還是一個很好的解釋不會傷害:)

+0

爲了避免將來出現這樣的問題,使用顯式可能會有幫助。 '明確的StubClass(weak_ptr x):b(x){c = 5;}'會馬上顯示出問題。 –

回答

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; 
} 

Run result

+1

但是,如果它們都是'NULL',則會返回'true'。我認爲這應該是'假'。 – rodrigo

+0

是的,你是對的。編輯答案。 – inkooboo

+0

對於遲到的評論,我很抱歉,但是爲什麼當'a == nullptr'時返回'true'而'b == nullptr'時是'false'? – Constructor

5

你原來的代碼段錯誤,因爲你不小心設置了一個無限循環:

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

沒有operator<weak_ptr。但是,您確實有從weak_ptrStubClass的隱式轉換。並且StubClass有一個operator<。所以這個函數無限期地調用自己:因此segfault。

從墨水筆目前接受的答案也將導致未定義的行爲,可能導致崩潰。由於weak_ptrs在您的程序執行過程中(與您的測試用例相關的內容比較多)變得過期,因此它們的排序會改變。當這種情況發生在set中的兩個weak_ptrs之間時,set將被損壞,可能導致崩潰。但是有這個使用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

+0

有趣。不知道智能指針的基於所有者的比較。在你的解決方案中,所有者對象的地址是比較而不是關鍵字符串。我不確定這是否是@bashrc的正確解決方案。順便說一句,對於這段代碼,看起來像set可能會在您的解決方案中被破壞,當擁有key的字符串的shared_ptr變得過時時。 – inkooboo

+1

當weak_ptr過期(最後一個shared_ptr釋放所有權)時,此比較**不會更改**。 weak_ptr繼續比較**與其他weak_ptrs完全相同的**。這是因爲weak_ptr引用的控制塊不會被釋放,直到最後一個* weak_ptr *被破壞/重置/重新分配爲止。 –