SORU
3 ŞUBAT 2014, PAZARTESİ


C 11 unordered_map ekler ne yok C standartları Komitesi tarafından hazırlanmıştır.

Çözüldü:Bu libstdc < v4 bir hata değildir.8.V4 GCC 2.Ve çınlama ^ 8 . = v3.2) eğer sistemde varsa kullanın. Rapor için http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57619 bkz. Doğru cevap verdiğin için Casey ve Brian için teşekkürler. Niall

Orijinal soru:

Sadece unordered_map::Ekle hayatımın üç gün çok garip bir hata izini kaybettim() değişkeni eklemek yok. Çok açık olmayan bu davranış çok çok yeni Derleyiciler yalnızca oluşur: 3.2-3.4 ve GCC 4.8 çınlama olduğunu buldumsadeceDerleyiciler bunu göstermek için "". özellik

Burada sorun gösterir: ana kod bölgeden bazı az kod

#include <memory>
#include <unordered_map>
#include <iostream>

int main(void)
{
  std::unordered_map<int, std::shared_ptr<int>> map;
  auto a(std::make_pair(5, std::make_shared<int>(5)));
  std::cout << "a.second is " << a.second.get() << std::endl;
  map.insert(a); // Note we are NOT doing insert(std::move(a))
  std::cout << "a.second is now " << a.second.get() << std::endl;
  return 0;
}

Muhtemelen en C programcıları gibi, çıktı böyle bir şey beklemiyordu:

a.second is 0x8c14048
a.second is now 0x8c14048

Ama 3.2-3.4 ve GCC 4.8 çınlama ile bu yerine alıyorum:

a.second is 0xe03088
a.second is now 0

Sen belgeleri unordered_map::eklemek için yakından incelemek kadar saçma, olabilir) aşırı yük 2 nerede http://www.cplusplus.com/reference/unordered_map/unordered_map/insert/:

template <class P> pair<iterator,bool> insert ( P&& val );

Evrensel referans hareket aşırı tüketen bir şey açgözlü bir diğer aşırı herhangi bir eşleştirme olduinşa taşıyınbir value_type. Neden bizim kod yukarıda muhtemelen en bekleneceği gibi bu aşırı ve unordered_map::value_type aşırı değil mi seçti?

Unordered_map::value_type bir çift< . karşısında cevap bakar: ^em>inş,:: shared_ptr^ int std . ve derleyici doğru çifti< düşünürdüm;intstd::shared_ptr>Cabrio değil. Bu nedenle derleyici hareket orijinal tahrip eden bir evrensel referans yük ve seçerrağmenprogramcı kullanarak std::move() bir değişken yok alma ile tamam olduğunu gösteren tipik bir sözleşme. Bu nedenle Ekle yok davranış aslındadoğruC 11 standardına göre, eski derleyicileri vardıyanlış.

Muhtemelen bu hatayı teşhis etmek için üç gün aldım şimdi görebilirsiniz. Değildi, her şey apaçık bir büyük kod tabanı nerede türü takılı içine unordered_map bir typedef tanımlanmış uzak kaynak kod açısından, ve oluştu asla kimse için, typedef oldu aynı value_type.

Yani Yığın Taşması soru:

  1. Neden eski derleyicileri değişken yeni Derleyiciler gibi eklenen yok değil mi? Hatta GCC 4.7 böyle yapmaz, ve oldukça uygun standartları.

  2. Bu sorun kesinlikle Derleyiciler yükseltme çalışmak için kullanılan kod aniden durmasına neden olacak, çünkü yaygın olarak bilinen, mi?

  3. C standartları Komitesi bu davranışın niyetinde mi?

  4. Nasıl unordered_map::Ekle önerirsiniz() daha iyi davranış vermek için değiştirilmesi? Eğer desteği varsa, WG21 N bir not olarak bu davranışı gönder ve onlara daha iyi bir davranış uygulamak için sormak istiyorum çünkü bu sorun.

CEVAP
3 ŞUBAT 2014, PAZARTESİ


Başkalarının yorumlarını, "evrensel" yapıcı, aslında, her zaman bağımsız hareket olmaması lazım. belirttiği gibi Bu aslında tartışılacak bir rvalue ve eğer bir lvalue eğer, kopyalamak, taşımak gerekiyor.

Her zaman hareket eden davranışları, gözlem, soru üzerine bir yoruma göre sabit olan libstdc bir hata. O meraklı için, g -4.8 başlıklarını bir göz attım.

bits/stl_map.h, çizgiler 598-603

  template<typename _Pair, typename = typename
           std::enable_if<std::is_constructible<value_type,
                                                _Pair&&>::value>::type>
    std::pair<iterator, bool>
    insert(_Pair&& __x)
    { return _M_t._M_insert_unique(std::forward<_Pair>(__x)); }

bits/unordered_map.h, çizgiler 365-370

  template<typename _Pair, typename = typename
           std::enable_if<std::is_constructible<value_type,
                                                _Pair&&>::value>::type>
    std::pair<iterator, bool>
    insert(_Pair&& __x)
    { return _M_h.insert(std::move(__x)); }

İkincisi yanlış std::forward kullanarak olması gereken yerde std::move kullanıyor.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Andytokkallos

    Andytokkallo

    27 Kasım 2007
  • StalkerJS

    StalkerJS

    15 HAZİRAN 2010
  • Tome Rodrigo

    Tome Rodrigo

    9 Temmuz 2006