2009-05-26 10 views
3

私はこのコードを持っている:次のコードはstd :: set "legal"を使用していますか?

set<int>::iterator new_end = 
        set_difference(set1.begin(), set1.end(), 
            set2.begin(), set2.end(), 
            set1.begin()); 
set1.erase(new_end, set1.end); 

これは、コンパイルし、Visual Studioで細かい実行されます。しかし、previous questionでは、人々はsetのイテレータがconstであると述べています。私は標準のようなことは何も見ません。誰かがそれがどこにあるか、あるいはこれが明確な行動であるかどうかを教えてくれますか?

そうでない場合は、必要なコードを入力してください。一時的なセットを作成せずにこれを行う方法はありますか?

答えて

7

あなたのコードは、set_differenceの2つの不変量に​​違反しています。 Josuttis Bookのページ420から:

  • 呼び出し側が先範囲が十分な大きさであるか、その挿入反復子が使用されていることを確認する必要があります。
  • 宛先範囲はソース範囲と重複してはなりません。

最初のセットを書き戻そうとしていますが、これは許可されていません。あなたは、ソースの範囲以外のどこかを記述する必要がある - 我々は第三のセットを使用することができますのために:std::inserterへの第2引数は要素を挿入する場所のヒントです

std::set<int> set3; 
std::set_difference(set1.begin(), set1.end(), 
        set2.begin(), set2.end(), 
        std::inserter(set3, set3.begin())); 

を。しかし、それは唯一のヒントです、しかし、要素が正しい場所に終わることを、安心してください。 set3は最初は空ですので、begin()は私たちが与えることができる唯一のヒントです。

set_differenceを呼び出した後、set3には、元のコードにset1が含まれているものが含まれます。必要に応じて、set3またはswapを使用してset1と続けることができます。

更新:

私はこれのパフォーマンスについてわからないんだけど、あなただけのset2に表示されset1からすべての要素を削除したい場合は、あなたが試すことができます:

for (std::set<int>::iterator i = set2.begin(); i != set2.end(); ++i) 
{ 
    set1.erase(*i); 
} 
1

set_differenceの5番目の引数はOutputIteratorとなります。documentationを参照してください。

4

いいえ、そうではありません。 SGI STL Reference

  1. [first1、last1)と[result、result + n]は重複しません。
  2. [first2、last2)と[result、result + n)は重複しません。

また、Nikolai N Fetissovが指摘したように、begin()をOutputIteratorとして使用できるかどうかはわかりません。それを解決するために

5

1つの提案:

std::set<int> tmp; 
std::set_difference(set1.begin(), set1.end(), 
        set2.begin(), set2.end(), 
        std::inserter(tmp, tmp.begin())); 
std::swap(tmp, set1); 

私は一時的なセットを(離れてコンテナを反復して行うことから、個々の要素に消去)を使用せずにそれを行うための方法を考えることはできません。

1

C++標準では、セットイテレータへの代入が禁止されていると明示的には言及していませんが、set_differenceに対して "結果の範囲は元の範囲のいずれかと重ならない"(25.3.5.3)と指定しています。

set1とset2の内容が幸運だったので、これまでのところうまくいくかもしれません。

関連する問題