2010-10-04 16 views
9

Bu istisna sınıfını kullandığımı söyleyelim:Birisi istisnalara ilişkin referans referanslarını açıklayabilir mi?

struct MyException : public std::exception 
{ 
    MyException(const std::exception &exc) : std::exception(exc) 
    { 
     cout << "lval\n"; 
    } 
    MyException(std::exception &&exc) : std::exception(std::forward<std::exception>(exc)) 
    { 
     cout << "rval\n"; 
    } 
}; 

... 
... 

try 
{ 
    throw std::exception("Oh no!"); 
    // above is rvalue since it's got no name, what if the throw is made as 
    // std::exception lvalExc("Oh wierd!"); 
    // throw lvalExc; 
    // if the throw is made thus, how can it be caught by catch(std::exception &&exc)? 
} 
catch(std::exception &&rValRef) 
{ 
    cout << "rValRef!\n"; 
    throw MyException(std::forward<std::exception>(rValRef)); 
} 

Değer yakalamaya çalıştığımda ( const) lvalue ref. derleyici, bu durumların rzue ref catch tarafından ele alındığını, bunun anlaşılabilir bir durum olduğunu çünkü bir istisnanın xvalue olduğunu ve belki de bir xvalue yakalamanın en iyi yolunun bir rıhtım ref (yanlışsa beni düzelt) olduğunu söyledi. Ama birisi yukarıdaki istisna oluşturma durumunda perfect forwarding hakkında açıklayabilir? Doğru mu? Derleme yapsa da, anlamlı mı yoksa yararlı mıdır? Kullandığım C++ kitaplığı, std::exception için bu tür bir kullanım için gerçekten hareket eden bir hareket yapıcıya sahip olmalı mı? İstisnalarla ilgili rvalue referanslar hakkında makaleler ve SO soruları aramayı denedim, bulamadım.

cevap

7

Aslında istisna işleme SolDeğerler ve SağDeğerler bakımından özel kuralları vardır. geçici durum nesnesi bir lvalue, mevcut taslak 15.1/3 görmek olup:

bir atış ifade geçici nesnesini başlatır, herhangi bir üst düzey cv çıkarılmasıyla belirlenir türü olan özel bir amacı, adı verilen - Atma işleneninin statik tipinden ve "T dizisi" veya "T döndüren fonksiyon" dan "T'ye gösterici" veya "T döndüren fonksiyona işaretçi" den türüne göre düzenleyiciler. Geçici bir değer'dir ve eşleşen işleyicide (15.3) belirtilen değişkeni başlatmak için kullanılır. Eğer istisna nesnesi türü eksik bir tipse veya (muhtemelen cv-kalifiye) dışında tamamlanmamış bir türden bir işaretçi ise, program kötü biçimlendirilir. Bu kısıtlamalar ve 15.3'te belirtilen tür eşleştirmesindeki kısıtlamalar hariç, atma işleneni tam olarak bir çağrıda (5.2.2) veya bir dönüş ifadesinin işleneni olarak bir işlev argümanı olarak ele alınır.

Ve rvalue referans olarak alıcı yasadışı de 15.3/1 bkz:

bir işleyici istisna-beyanname o işleyici girilecek neden olabilir istisnalar tipini (lar) anlatılmaktadır . Kural dışı durum bildirimi, eksik bir tür veya numaralı bir referans türünü belirtmez. Özel durum bildirimi, void *, const void *, volatile void * veya const volatile void * dışındaki tamamlanmamış türde bir işaretçi veya referansı göstermez.

Ayrıca, mükemmel yönlendirme anlamak için görünmüyor. İleri çağırma, bir hamleden daha iyi değildir. Mükemmel yönlendirme fikri, argümanın değer kategorisini türün bir parçası olarak kodlamaktır ve şablon argüman indirgemesinin bunu çözmesine izin vermektir. Ancak istisna işlemciniz bir işlev şablonu değildir ve olamaz.

Temelde, mükemmel yönlendirme şablon argümanı kesinti ve rvalue referanslar dayanır: argümanın değeri kategorisine bağlı olarak

void inner(const int&); // #1 takes only lvalues or const rvalues 
void inner(int&&);  // #2 takes non-const rvalues only 

template<class T> 
void outer(T && x) { 
    inner(forward<T>(x)); 
} 

int main() { 
    int k = 23; 
    outer(k); // outer<T=int&> --> forward<int&> --> #1 
    outer(k+2); // outer<T=int> --> forward<int> --> #2 
} 

, şablon argumend kesinti T bir lvalue referans veya normal değer türü ya olmaya deduces. Referans çöken nedeniyle, T & & da ilk durumda bir lvalue referansı veya ikinci durumda rvalue referansıdır. T & & görmek ve T sonucuna varılabilir bir şablon parametresi ise, bir "her şeyi yakalamak" temelde bu.std :: forward, orijinal değer kategorisini (T olarak kodlanmış) geri yükler, böylece argümanı aşırı yüklenen iç işlevlere mükemmel bir şekilde iletebilir ve doğru olanı seçebiliriz. Ancak bu sadece dışsal bir şablon olduğu için ve değer kategorisine göre T'yi belirlemek için özel kurallar olduğu için işe yarar. Şablonlar/şablon argümanı indirimi olmadan (# 2'de olduğu gibi) bir rvalue referansı kullanırsanız, işlev sadece r değerleri kabul eder.

+1

+1: Söylediğimi söylüyorsun ama daha çok ve daha iyi. Ayrıca, yalnızca tavsiyeyi açıkça belirtmek için, düz bir const olmayan başvuru eşleşir ve istisna nesnesini değiştirebilir. – Potatoswatter

+0

@Potatoswatter: Cevabınızın yarısını tekrar ettiğim için üzgünüm. Cevabınızı gözden geçirdiğimde 15.1/3'e referansınızı kaçırdım. – sellibitze

+0

@sellibitze: Onları karşılıklı olarak münhasır hale getirmenin bir anlamı yok. Cevabınız doğru olduğu sürece herhangi bir şeyi ödünç almakta özgürsünüz: v). – Potatoswatter