2013-01-22 18 views
11

Dizilerin fonksiyonel tarzı oluşturulmasında bazı kodlar yazmaya çalışıyordum. Bir işlev, range(a, b) yazdım, bir nesne döndürdüğünüz bir nesneyi döndürür, foreach stili, a, a + 1, ..., b - 1 sayıları boyunca ilerler. Sonra başka bir işlev yazdım, map(f, t) Sekanstaki her bir elemanın, f numaralı telefonun yinelenen nesnesinin t karşılık gelen elemanı ile aranmasının bir başka yinelenen nesnesi.Neden gcc bu özel yineleyici kullanarak bu C++ 11 foreach döngüsünü optimize eder?

-O1 veya daha düşük bir sürümü kullanarak derlerseniz bu beklendiği gibi çalışır; -O2 veya üstü ile, foreach döngüsüm (altta main'da) tamamen en iyi duruma getirilir ve hiçbir şey yazdırılmaz. Bu neden oluyor, neyi yanlış yaptım? mevcut yorumların Özetle

template<typename T> 
struct _range { 
    T a; 
    T b; 

    _range(T a, T b): 
     a(a), 
     b(b) 
    { 
    } 

    struct iterator { 
     T it; 

     iterator(T it): 
      it(it) 
     { 
     } 

     bool operator!=(const iterator &other) const 
     { 
      return it != other.it; 
     } 

     void operator++() 
     { 
      ++it; 
     } 

     T operator*() const 
     { 
      return it; 
     } 
    }; 

    iterator begin() const 
    { 
     return iterator(a); 
    } 

    iterator end() const 
    { 
     return iterator(b); 
    } 
}; 

template<typename T> 
_range<T> range(const T a, const T b) 
{ 
    return _range<T>(a, b); 
} 

template<typename F, typename T> 
struct _map { 
    const F &f; 
    const T &t; 

    _map(const F &f, const T &t): 
     f(f), 
     t(t) 
    { 
    } 

    struct iterator { 
     const F &f; 
     typename T::iterator it; 

     iterator(const F &f, typename T::iterator it): 
      f(f), 
      it(it) 
     { 
     } 

     bool operator!=(const iterator &other) const 
     { 
      return it != other.it; 
     } 

     void operator++() 
     { 
      ++it; 
     } 

     int operator*() const 
     { 
      return f(*it); 
     } 
    }; 

    iterator begin() const 
    { 
     return iterator(f, t.begin()); 
    } 

    iterator end() const 
    { 
     return iterator(f, t.end()); 
    } 
}; 

template<typename F, typename T> 
_map<F, T> map(const F &f, const T &t) 
{ 
    return _map<F, T>(f, t); 
} 

#include <algorithm> 
#include <cstdio> 

int main(int argc, char *argv[]) 
{ 
    for (int i: map([] (int x) { return 3 * x; }, range(-4, 5))) 
     printf("%d\n", i); 

    return 0; 
} 
+0

Belki bir hata? Clang ++ ile, hem O1 hem de O2 optimizasyon seviyelerinde çalışır. –

+7

'_map' üyelerini const refs depolamak yerine değerlerine göre depolamayı deneyin. ('Range' nesnesinin umduğundan daha önce yok edildiğinden şüpheleniyorum.) – ildjarn

+3

inanıyorum inanıyorum: @ildjarn haklıydı: geçici olarak bağlı olduğu sabit referans olduğu sürece yaşamak zorunda kalıyor. bağlandığı referans, 'haritanın kurucusunun argümanıdır. Kurucu geri döndüğünde, referans kapsam dışı kalır ve geçici olarak yok olur. –

cevap

8

:

range(-4, 5) (çoğu durumda) geçici oluşturur ve oluşturuldukları tam ifadesinin sonuna kadar yalnızca canlı Temporaries İşte benim kod. Durumunuzda, geri verilen _range nesnesi, _map'un yapısı sırasında geçerlidir, ancak _map belirtildiği anda map'dan döndürüldüğünde, tam ifade biter ve _range nesnesi yok edilir. undefined behavior klasik - _map const ref tarafından yerine değeriyle onun kurucusuna geçirilen argümanları tutan çünkü söz konusu

, bu senin _map::t zaten sallantıda bir başvuru olduğunu, zaman aralığı tabanlı for yürütmeye başlar anlamına gelir.

Bunu düzeltmek için, veri üyelerini değerlere göre _map saklayın.