G ++ компилирует неправильный код STL - PullRequest
1 голос
/ 10 января 2012

Я думаю, что нашел ошибку G ++, но я не уверен. Я не могу это объяснить. Компиляция не должна передавать плохой код, но это так. g ++ - 4.5 и g ++ 4.6 -std = c ++ 0x передают этот код без предупреждения.

Поскольку компиляция считает, что указатель на объект 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;
     }

1 Ответ

0 голосов
/ 10 января 2012

bind2nd объявляется как:

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

Это означает, что тип T выводится, в данном случае как Bar *.

В моей системе это реализовано так:

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));
} 

Чтобы понять, почему это скомпилируется, рассмотрим:

class Bar {};

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

, которая кажется реальной проблемой и компилируется с g ++, потому что это в основном reinterpret_cast.

Самый простой обходной путь - это использовать boost::bind (или std::bind для C ++ 11):

#include <boost/bind.hpp>

...

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

или лямбда-функция выводит ошибку, которую вы ожидаете увидеть.

...