2015-11-23 4 views
5
#include <iostream> 
#include <map> 

int main(int argc, char** argv) 
{ 
    std::map<int, int> map; 
    map.emplace(1, 1); 
    auto reverse_iter = map.rbegin(); 
    std::cout << reverse_iter->first << ", " << reverse_iter->second << std::endl; 
    map.emplace(2, 2); 
    std::cout << reverse_iter->first << ", " << reverse_iter->second << std::endl; 

    return 0; 
} 

これはアウト出力しますこれは適切な動作ですか? std ::マップイテレータの無効化

1, 1 
2, 2 

はこれが標準によると、起こることになっているものは本当にですか?私はreverse_iter触れていないよ、それがポイントの値が変化しています。私はSTDにイテレータを考え::マップが挿入に対して安全であることになっていました。しかし、むしろ、「この時点でマップの最後であることを起こるものは何でも」するために、私はそれを告げた値を指して滞在することはないというreverse_iterを決定しているようです。

更新:(どのような状況で、私は見つけるように見えることができます)、これは前方イテレータで発生していないようだ、と私のgccのバージョンは5.1.1-4です:更なる情報、ケースには重要。

+0

「無効化」であると、新しいデータを指すが、同じものではありません、彼らは何ですか?これは、コンテナ内の最後のペアへの有効なポインタです。そのペアはちょうど変わったことが起こります。 – tadman

+0

フォワードイテレータでは発生しません。 rbeginをbeginで置き換え、(2、2)を(0、0)で置き換えます。また、標準に準拠していますか?それは本当に予期せぬことであるので、確かです。 – KarenRei

+0

あなたがマップに入れた最初のものは変更されません。しかし、あなたがやった最後のことができます。 – tadman

答えて

3

引用され、ここでhttp://en.cppreference.com/w/cpp/container/map/rbegin

リバースイテレータはそれが実際に

を指し、1以上の次の要素へのイテレータを格納したような副作用は、(あなたがそのイテレータの前に何かを挿入した場合ということでしょう最後の())inclidingときその逆イテレータデリファレンスあなたがその新しい値が表示されます。この場合、逆の反復子は無効とは思われません。

+0

それで、基本的に、それは設計によって壊れていますか? :使用しているイテレーターの隣にあるものを変更すると、使用しているイテレーターを変更できますか? グレート...:Þ しかし、それは、標準が言う私にできること何もない場合。 – KarenRei

+0

私はあなたが「有効」と「一貫」を混同していると思います。 Invalidは非常に特殊なものです。つまり、定義されていない動作を引き起こすため、イテレータを使用しないでください。イテレータが指し示すものが地図を操作した後も変化しないとのあなたの期待は満たされていませんが、それは標準の問題ではありません。 – tadman

+0

イテレータの目的は、ポインタとインデックスの代用として機能することを前提としていますが、指していないものを変更しているときに変更する標準が非常に壊れていると言います。また、順方向反復子と逆方向反復子の間で動作が矛盾していることも非常に壊れているとも言えます。しかしそれはそれです。 – KarenRei

4

C++標準(23.2.4連想コンテナ)

9によると、インサートとメンバーがコンテナに イテレータと参照の有効性に影響を与えないものとし、消去メンバーは のみ無効とするものと据え付けますイテレータ、および消去された要素への参照です。一方

(24.5.1リバースイテレータ)

1クラステンプレートreverse_iteratorは 先頭に、その根底にある反復子によって定義された配列の端から を反復するイテレータアダプタでありますそのシーケンス。

約クラスstd::reverse_iteratorについては、同じことが標準コンテナの逆イテレータに有効です。表97によると

- リバーシブルコンテナの要件

rbegin()だからあなたの例では逆イテレータはまだend()に対応reverse_iterator(end())

に対応しています。 `

1

map.rbegin()std::reverse_iterator(map.end());

に等しいイテレータを返すとき、あなたの問題は、逆イテレータを逆参照が発生します。 reverse_iteratorを逆参照すると、実際に得られる値はイテレータから得られ、その値がreverse_iteratorの内部に格納されます。それは奇妙に思えるが、良いの理由であり、それは避けられないですかもしれません。これは、範囲の過去端の要素を配置するためのものです。逆の場合、範囲内の終わりの要素を指すイテレータは、最後の要素(それを超えていない)を指しています。範囲(これは逆の範囲の最初の要素です)。また、ある範囲内の最初の要素のイテレータが逆転した場合、逆イテレータは最初の要素の前の要素を指します(これは、逆の範囲の終わりの要素です)。 reverse_iterを逆参照するとき、あなたの場合には、

はやって同等です:

*(--map.end()); 

その結果、第2 emplace後のマップの最後の要素を変更し、逆参照している(--map.end())(すなわち、あなたのreverse_iter)あなたを地図の新しい最後の要素を取得します。

0
std::map<int, int> map2; 
map2.emplace(2, 2); 
auto fiter = map2.begin(); 
std::cout << fiter->first << ", " << fiter->second << std::endl; 
map2.emplace(1, 1); 
std::cout << fiter->first << ", " << fiter->second << std::endl; 
fiter = map2.begin(); 
std::cout << fiter->first << ", " << fiter->second << std::endl; 

プリント

2, 2 
2, 2 
1, 1 
関連する問題