読者です 読者をやめる 読者になる 読者になる

it->とか書いたことないなぁ(多分嘘)

c/c++

きむら(K)さんのところから。

STLの解説とかで (*it).first とか書いてあるのはあくまで説明用であって普通は it->first と書く。

  • > 演算子を使った場合には解析でドジじる場合がある (多重定義されたとき?)ので前者のように書け。 とどこかで見たようなおぼえがあるんだけど。 おしえてえらいひと。
404 Not Found

あら、説明用というか、なんというか、できるだけアロー演算子(なんか懐かしい響き)などというおかしなものに囚われたくないので、
ドットでアクセスしてたけど。
おしえてエロイ人!

operator->が定義できるが、operator.は定義できないのが、C++の節操だと思っている昨今でござる。

と、酒を飲んでいる勢いで書いたけれど、思い出した。

  • >で書いた場合、連想コンテナにおいて問題が発生することがある。

例えばsetなのだけれど、要素はconstでないのだが、実装によってはconstであることがある。
標準化委員会ではset/multisetの値はconstにしない、と決めているのにも関わらずだ。(map/multimapのキーはconst)

typedef set<Hoge> HogeSet;
HogeSet hogeSet;
Hoge selectedId;

...

HogeSet::iterator it = hogeSet.find(selectedId);
if (it != hogeSet.end()) {
    it->setTitle("Foo");    // 実装によってはこれがコンパイルできない!!!!
}

で、Effective STLではこう言っている。

  • 移植性が問題ではない場合、setまたはmultisetの要素の値を変更しようとし、STLの実装で変更が可能なら、そのまま実行しよう。要素のキー部分、つまりコンテナのソート順に関係する要素の部分を変更しないことだけには注意しよう。
  • 移植性が問題である場合、setとmultisetの要素は変更できない。(少なくともキャストなしでは変更できない)と仮定しよう。

で、ここで重要なのが「参照」にキャストしなければならない、ということ。

if (it != hogeSet.end()) {
    const_cast<Hoge>(*it).setTitle("Foo");
}

このコードはitが指すオブジェクトを撮り、キャストの結果をHogeに対する参照として扱うようにコンパイラに指示できる。
itはポインタではなくiteratorなので

const_cast<Hoge*>(it)->setTitle("Foo");

がうまくいかない事に注意せよ。
手元のgccやcwでもsetの要素は変更できなかった。

以下にテストコードを示す。

class Hoge {
public:
    Hoge(int id) : id_(id), title_("Hoge") {}
    int id() const { return id_; };
    const string& title() const { return title_; }
    void setTitle(const string& title) { title_ = title; }
private:
    int id_;
    string title_;
};

struct IdLess:
    public binary_function<Hoge, Hoge, bool> {
    bool operator() (const Hoge& lhs,
                     const Hoge& rhs) const
    {
                        return lhs.id() < rhs.id();
    }
};

typedef set<Hoge, IdLess> HogeSet;

int main()
{
    
    
    HogeSet hogeSet;
    Hoge selectedId(1);
    
    Hoge hoge0(0);
    Hoge hoge100(100);
    Hoge hoge3(3);
    Hoge hoge1(1);
    
    hogeSet.insert(hoge0);
    hogeSet.insert(hoge100);
    hogeSet.insert(hoge3);
    hogeSet.insert(hoge1);
    
    HogeSet::iterator it = hogeSet.find(selectedId);
    if (it != hogeSet.end()) {
        //it->setTitle("Foo");    // これはコンパイルできない!
        const_cast<Hoge&>(*it).setTitle("Foo");    // 正しい!
        //const_cast<Hoge*>(it)->setTitle("Foo"); // これもコンパイルできない!
    }
    
    for (HogeSet::iterator it = hogeSet.begin(); it != hogeSet.end(); ++it) {
        cout << (*it).title() << endl;
    }
}

普段は->でいいんじゃねー、って話があるかもしれんけど。