std::set.find()とstatic_cast<>の一時変数返しの謎

std::set.find()

std::set の要素内容を変更できないの?と会社で言われて調べてみる。

std::set<A> sa ;
std::set<A>::iterator it ;
it = sa.find( 5 ) ;
(*it).set_prop(7) ;

で問題なく更新できる(VC6)。ただし、setの内部実装はバイナリツリーだからキーは書き換えちゃいけません。
と思ったら、先輩の環境ではset_prop()を呼び出せない。どうやらg++ version 3.4.1(うろ覚え)ではset.find()がconst iterを返すらしい。

it = sa.find( 5 ) ;
((A)(*it)).set_prop( 7 ) ;

キャストでコンストはずせば大丈夫かと思いきや、実行しても要素内容が変わらない。この時点でsetは内部のバイナリツリーの構成が矛盾を起こさないように、set.find()はコピーを返すんだろうと推測し諦めた。けれども、const iterを返すのにコピーを返すのはおかしい(constなら書き換えられないはずだからコピーを返す必要がない、逆に言うとconst iterでない場合にコピーを返すのなら妥当だと思われる)と思い、もう一度調べ直してみた。するとconst_castを使えばOKとのこと。

it = sa.find( 5 ) ;
const_cast<A &>(*it).set_prop( 7 ) ;

これでOK。ただし、移植性などを考えると、remove()してinsert()するのが礼儀っぽい。
というか、(A)のキャストで成功しないのは一時変数が返されるのが原因っぽい。(A &)なら処理系によってはOK(VC6)。

static_cast<>の一時変数返し

string str("test") ;
(string)str = "modify" ;

これで、strの値が変更されないってのが驚き。ちゃんと決められてる事なんだけども。static_cast()キャストは一時変数を返すのは仕様。いつかハマらないようにメモとして残す。