2012-01-10 14 views
1

私はG ++バグを見つけたと思いますが、わかりません。私はそれを説明することはできません。コンパイルはBADコードを渡すべきではありません。 g ++ - 4.5およびg ++ 4.6 -std = C++ 0xは、このコードを警告なしで渡します。G ++は間違ったSTLコードをコンパイルします

これは、BarオブジェクトへのポインタがBarオブジェクトそのものだと考えています。 私は狂っています。私はバグを取得するために多くの時間を費やしました。この種のバグから保護する方法はありますか?

不正コードが得られます。

g++-4.6 for_stackoverflow.cpp && ./a.out 
address of bar in main() 0xbff18fc0 
Foo 0x9e80008  Bar  0xbff18fec 
Foo 0x9e80028  Bar  0xbff18fec 
Foo 0x9e80048  Bar  0xbff18fec 
end 

ソースコード:

 #include <iostream> 
    #include <list> 
    #include <iomanip> 
    #include <algorithm> 

    #define BAD 

    using namespace std; 

    class Bar; 

    class Foo { 
    public: 
     virtual void tick(Bar & b) { 
     cout << "Foo " << this << "  Bar " << setw(14) << (&b) << endl; 
     }  
    }; 

    class Bar : public list<Foo*> { 
    }; 

    int main() { 
     Bar bar; 
     cout << "address of bar in main() " << &bar << endl; 
     bar.push_back(new Foo()); 
     bar.push_back(new Foo()); 
     bar.push_back(new Foo()); 
    #ifdef GOOD 
     for_each(bar.begin(), bar.end(), bind2nd(mem_fun(&Foo::tick), bar)); 
    #elif defined(BAD) 
     for_each(bar.begin(), bar.end(), bind2nd(mem_fun(&Foo::tick), &bar)); 
    #else 
    #error "define GOOD xor BAD" 
    #endif 
     cout << "end" << endl; 
     return 0; 
    } 

答えて

0

bind2ndは次のように宣言されています。

template <class Fn, class T> 
binder2nd<Fn> bind2nd(const Fn&, const T&); 

これはタイプTが推測されていることを意味し、この場合のようにBar *。私のシステムで

次のように実装されています:

class Bar {}; 

int main() { 
    Bar *b = 0; 
    typedef const Bar& type; 
    const type t = type(b); 
} 

本当の問題のようですし、G ++でコンパイルしないこれ、it's basically a reinterpret_castので:それは検討してコンパイルする理由を確認するには

template<typename _Operation, typename _Tp> 
inline binder2nd<_Operation> 
bind2nd(const _Operation& __fn, const _Tp& __x) 
{ 
    typedef typename _Operation::second_argument_type _Arg2_type; 
    return binder2nd<_Operation>(__fn, _Arg2_type(__x)); 
} 

最も単純な回避策は、それが(C++ 11またはstd::bindboost::bindを使用するように変更される:

#include <boost/bind.hpp> 

...

boost::bind(mem_fun(&Foo::tick), _1, &bar) 

またはラムダ関数がエラーを与えませんあなたは見たいと思うだろう。

+0

bind2ndの引数の型は実際の引数の型から推論されています。そして、それはチェックと注意を払わずに別のものに急激に変換されます。これは本物の落とし穴です:(。次のようにchar x; float f; f = *((float *)(void *)&x); –

+0

@ DaneelS.Yaitskov - 標準では、 'static_cast (x)'の代わりに 'std :: bind1st'/'std :: bind2nd'が廃止される理由の1つと考えられます'C++ 11で – Flexo

関連する問題