2009-06-20 8 views
4

セット内の要素の値が変更された場合、順序が正しくない可能性があります。この小さなプログラムに示すように、std ::を 'リフレッシュ'するように指示する方法?

#include <algorithm> 
#include <iostream> 
#include <set> 
#include <string> 

struct Comp 
{ 
    bool operator()(const std::string * lhs, const std::string * rhs) 
    { 
     return *lhs < *rhs; 
    } 
}; 

int main() 
{ 
    typedef std::set<std::string*, Comp> MySet; 
    MySet mySet; 

    std::string * a = new std::string("a"); 
    mySet.insert(a); 

    std::string * c = new std::string("c"); 
    mySet.insert(c); 

    std::string * b = new std::string("b"); 
    mySet.insert(b); 

    for (MySet::iterator it = mySet.begin(); it != mySet.end(); ++it) 
    { 
     std::cout << *(*it) << std::endl; 
    } 

    // Ouput has correct order: 
    // a 
    // b 
    // c 


    *b = "z"; 
    std::cout << std::endl; 

    std::string * d = new std::string("d"); 
    mySet.insert(d);  

    for (MySet::iterator it = mySet.begin(); it != mySet.end(); ++it) 
    { 
     std::cout << *(*it) << std::endl; 
    } 

    // Output no longer ordered correctly: 
    // a 
    // d 
    // z 
    // c 

    return 0; 
} 

内部のソートを 'リフレッシュ'するにはどうすればよいですか?

+0

値は変更しないでください。 'value_type'は' std :: set 'でなければなりません。(VSはそれに従わないと思いますが) –

+0

値の型はユーザーが渡したもので、トップレベルのconstが追加されています。ユーザが 'std :: string *'を渡すと、値の型は 'std :: string * const'になります。ユーザーが値のソート位置の不変性を強制しないものを渡すことを禁じるルールはありません。このような方法で値を変更すると、未定義の動作が発生するというルールがあります。 –

答えて

9

ここに非常に類似した対象(なく、かなり重複するものの、カスタム比較で可変オブジェクトへのポインタを保存しているため):

what happens when you modify an element of an std::set?

基本的に、あなたがしようとしている何をしていませんする。代わりに、setがポインタを保持しているオブジェクトを変更する場合は、最初にポインタを削除してオブジェクトを変更してから、ポインタを再挿入します。

5

単純に、あなたはできません。アイテムをセットに配置する場合は、アイテムの順序を変更する方法でアイテムを変更しないでください。このようにアイテムを変更する必要がある場合は、セット(set :: erase)からアイテムを削除し、新しいアイテム(std :: insert)を新しい値で再挿入する必要があります。

1

vs 2008を使用している場合、std::set実装では非constイテレータがサポートされているため、記述するコードをそのライブラリを使用して正常にコンパイルできます。他のstl実装(例えば、sgi's)では、set::const_iteratorset::iteratorは、新しいキー値を明示的に設定することについて不平を言う同じタイプです。

+1

セットイテレータは標準でconstです。イテレータを介してセットのメンバーを更新しようとすると、コンパイルエラーが発生するはずです。 – jkp

0

異なる比較述語を使用してそれ自身にコピーします。通常、これは例えば、異なる比較演算を指定するために使用され

std::set MySet(); 

/* add entries*/ 

MySet = std::set(MySet.begin(), MySet.end(), Comp); 

は、保存されたクラス/構造体の別の部分を使用して、それをソートします。

+0

NB。これは、単一のアイテムを削除して変更してから再追加するよりもはるかに高額になります。 –

+0

これがMySetの変更につながる場合、それは既に定義されていません。 – sehe

+0

'std :: set <...> MySet();は**変数ではありません**関数宣言です!! – ikh

2

セット内の要素の値が

停止を変更した場合!これは法的に発生することはありません。

std::setは、手作業での再注文は決して必要ではないという前提条件のため、あなたが求めていることをする手段を提供していません。

関連する問題