Subscribed unsubscribe Subscribe Subscribe

invalid iterator同士の比較2

結局、上の問題への対処として、適当な空コンテナを作って、そいつのイテレータを有効でないイテレータとして扱う事で逃げようとしたんだけどそれでも依然例外が出る。テストコードは以下。さすがにこれが通らないと仕様に合致しているとは言えないだろう。

#include <typeinfo>
#include <iterator>
#include <iostream>
#include <vector>
#include <map>

template<typename Titer_>
struct get_iterator_category {
    typedef typename Titer_::iterator_category type;
};

template<typename Tany_>
struct get_iterator_category<Tany_*> {
    typedef std::random_access_iterator_tag type;
};

template<typename Tcontainer_>
void put(Tcontainer_& target, typename Tcontainer_::value_type const& value)
{
    target.push_back(value);
}

template<typename Tkey_, typename Tval_>
void put(std::map<Tkey_, Tval_>& target, typename std::map<Tkey_, Tval_>::value_type const& value)
{
    target.insert(value);
}

template<typename Tcontainer_>
void iterator_test1()
{
    Tcontainer_ empty1, empty2;
    typedef typename Tcontainer_::const_iterator const_iterator;
    std::cout << typeid(const_iterator).name() << std::endl;
    std::cout << typeid(typename get_iterator_category<const_iterator>::type).name() << std::endl;
    std::cout << empty1.size() << std::endl;
    std::cout << empty2.size() << std::endl;
    std::cout << (empty1.begin() == empty2.begin() ? "yes!": "hmm..") << std::endl;
}

template<typename Tcontainer_>
void iterator_test2()
{
    Tcontainer_ nonempty1, nonempty2;
    typedef typename Tcontainer_::const_iterator const_iterator;
    put(nonempty1, typename Tcontainer_::value_type());
    put(nonempty2, typename Tcontainer_::value_type());
    std::cout << typeid(const_iterator).name() << std::endl;
    std::cout << typeid(typename get_iterator_category<const_iterator>::type).name() << std::endl;
    std::cout << nonempty1.size() << std::endl;
    std::cout << nonempty2.size() << std::endl;
    std::cout << (nonempty1.begin() == nonempty2.begin() ? "yes!": "hmm..") << std::endl;
}

int main(int, char**)
{
    iterator_test1<std::vector<int> >();
    iterator_test1<std::map<int, int> >();
    iterator_test2<std::vector<int> >();
    iterator_test2<std::map<int, int> >();
    return 0;
}

よくよく調べてみると、_SCL_SECURE_VALIDATE()というマクロによるassertionで失敗し、_SCL_SECURE_INVALID_ARGUMENT_NO_ASSERTマクロの処理に移り、最終的に_SCL_SECURE_INVALID_PARAMETERが呼ばれているようだ。

そのassertionとは...

(VC++vectorのソースからの抜粋)

    bool operator==(const _Myt& _Right) const
        {   // test for iterator equality

 #if _HAS_ITERATOR_DEBUGGING
        _Compat(_Right);
 #else
        _SCL_SECURE_VALIDATE(this->_Mycont != NULL && this->_Mycont == _Right._M
ycont);
 #endif /* _HAS_ITERATOR_DEBUGGING */

        return (_Myptr == _Right._Myptr);
        }

_Mycontというメンバ変数が属するコンテナへのポインタとなっている。いや、これは余計なお世話というものだ。単なるパラノイドだ。

余談だけどg++ 3.4.4のlibstdc++でも4.2.1のlibstdc++でも最初のテスト (iterator_test1 >) での異なるコンテナに属するイテレータ同士の比較で true が返ってきた。いいんかなこれは。バグっぽいなー。