2010-08-10 37 views
1

請考慮以下程序。它創建一組指針到ints,並使用自定義的indrect_less比較器,通過指向整數的值對集合進行排序。一旦完成,我然後改變其中一個指向整數的值。然後,可以看到集合的順序不再被排序(我想因爲集合不知道有什麼改變)。通過間接使指針無效

(不介意的C++ 0x循環,我在VS2010運行)

#include <iostream> 
#include <set> 
using namespace std; 

struct indirect_less { 
    bool operator()(int* l, int* r) const 
    { 
     return *l < *r; 
    } 
}; 

int main() 
{ 
    set<int*, indirect_less> myset; 

    int* a = new int(5); 
    int* b = new int(6); 
    int* c = new int(7); 

    myset.insert(a); 
    myset.insert(b); 
    myset.insert(c); 

    cout << "Set contains: "; 
    // (outputs: 5 6 7) 

    for (auto i = myset.begin(), end = myset.end(); i != end; ++i) 
    { 
     cout << **i << " "; 
    } 

    cout << endl << "Modifying *a" << endl; 
    *a = 9;   // point of interest 
    cout << "Set contains: "; 
    // (outputs: 9 6 7 - unsorted order) 

    for (auto i = myset.begin(), end = myset.end(); i != end; ++i) 
    { 
     cout << **i << " "; 
    } 

    cout << endl; 

    cin.get(); 

    return 0; 
} 

1)我說得對,我調用未定義的行爲? myset整行狀態是否爲*a = 9;後無效?

2)是否唯一正確的方法來擦除然後重新插入a

3)有沒有辦法,一旦*a = 9;已經運行,重新平衡集合到排序順序,具有明確定義的行爲?

+1

我會去是的,是的,No. – 2010-08-10 16:39:05

+0

該行後面定義的行爲?例如,你可以可靠地遍歷集合(具有未定義的順序)嗎? – AshleysBrain 2010-08-10 16:47:27

+0

未定義不會以這種方式工作。一旦您調用未定義的行爲,所有投注都將關閉。你的程序可能會做任何事情,包括似乎繼續工作。直到它沒有。通常在爲別人演示代碼時很重要。 – KeithB 2010-08-10 19:46:03

回答

2

是的,std::set假設元素是不可變的。這是possible,如果有危險,每次更改後要自行重新排序。但我不會推薦它:使用另一種集合類型。

1

1)是的,設置不允許修改它的元素。

2)除了刪除舊值並插入新值之外,還可以用新構造的舊集替換舊集。

3)沒有

1

1)我不知道行爲是不確定的。這個例子中的額外扭曲是該集合中的元素沒有改變 - 集合中的每個元素都是一個指針。如果你在執行行'* a = 9'之前和之後打印出集合的(指針)元素,我相信你會發現指針值在賦值之前和之後的順序是相同的。這是發生在這個集合的主體之外,所以這個集合沒有辦法維持你想要的順序。

2)合格的「是」,這將強制使用indirect_less()來排序集合中的元素,同樣要注意的是,你要通過每個解除引用的指針的值來排序集合中的元素,但是這會讓我覺得有點冒險,因爲你描述的原因

從打印輸出中的圖例「Set contains:」中,我推測這個例子s縮小以形成一組整數。然而,所定義的集合,即「集合」實際上包含指向整數的指針,而不是整數本身。我認爲理想和實際收藏之間的這種錯位是問題的根本原因。

3)參見2)。