2015-12-09 29 views
6

Bir kaynağın kendisine verilen herhangi bir akıştan yüklenmesi için bir kurucu oluşturmaya çalışıyorum. İstream parametresini yapıcıya iletmenin en iyi yolunu anlayamıyorum.Bir std :: istream'i bir işlev içine nasıl geçerek geçici olarak geçmesine izin verebilirsiniz?

Loader::Loader(istream stream); 

Bu, nesne dilimlemesinden dolayı kötüyse kötüdür, bu nedenle seçenek yoktur.

Loader::Loader(istream& stream); 

Şimdi kullanıyorum ve oldukça iyi görünüyor. Bununla birlikte önemli bir sorun var - geçici olmayan bir referansa geçici olarak bağlanamazsınız çünkü geçici olmayan referanslara bağlanamazsınız! Örneğin, aşağıdaki çalışmaz: Ben şimdi sadece ömrünü uzatmak için konteynerin bir üyesi değişkeni olarak ifstream saklamak zorundayım çünkü

Container(): 
    mLoader(ifstream("path/file.txt", ios::binary) 
{ 
} 

Bu bir sınırlama doğrusu olduğunu.

Loader::Loader(const istream& stream); 

Ama vb .seek() olmayan const olduğundan, bu da bir seçenek değildir ...

: problem yana

biri olsa bu olabilir, const olmayan referanslarla olduğunu

Peki, bu problem nasıl düzgün bir şekilde çözülebilir?

+2

'std :: istream' bir yerde mevcut olmalıdır. – Simple

cevap

7

Derleyiciniz C++ 11 veya daha iyiyse, istream değerini alan kurucunun bir sürümünü sağlamanız yeterlidir.

void Loader::Loader(std::istream&& is)

hızlı bir örnek:

#include <iostream> 
#include <iomanip> 
#include <string> 
#include <sstream> 

struct Loader 
{ 
    Loader(std::istream& is) 
    { 
     read(is); 
    } 

    Loader(std::istream&& is) 
    { 
     read(is); 
    } 

    void read(std::istream& is) 
    { 
     is >> std::quoted(x); 
     is >> std::quoted(y); 
    } 

    std::string x, y; 
}; 

std::ostream& operator<<(std::ostream& os, const Loader& l) 
{ 
    os << "x = " << l.x; 
    os << ", y = " << l.y; 
    return os; 
} 


auto main() -> int 
{ 
    using namespace std; 

    Loader l(istringstream(R"text("donkey" "horse")text")); 
    cout << l << endl; 

    istringstream not_temp(R"text("apple" "banana")text"); 
    Loader l2(not_temp); 
    cout << l2 << endl; 

    return 0; 
} 

beklenen çıktı:

r-değeri referans olarak
x = donkey, y = horse 
x = apple, y = banana 
+0

Bu IMO anlamlıdır. Bir Loader :: Loader (std :: istream && is) ve Loader :: Loader (std :: istream & is) öğelerini hem sağlayarak hem de daha önce bu ikinciyi arayarak, her iki şekilde de kullanabilirsiniz. Teşekkürler! – Tobias

+0

İstenen her sınıf için böyle bir kurucuyu tanımlamanın noktasını göremiyorum. Gördüğüm gibi, “temp_ref” işlevi gibi tek bir merkezi çözüm, daha az kod (sınıfların lineer olarak) ve daha açık. –

+0

Konumunuzu anlıyorum. Daha az kod (doğrusal olarak vaka sayısında) Katılıyorum. Daha açık, muhtemelen sorunu alacağım. –

2

Örnek

Container(): 
    mLoader(ifstream("path/file.txt", ios::binary) 
{ 
} 

& hellip; Kötü düşünülmez, çünkü geçici sürenin ömrü sadece yapıcı çağrısı olur. Sonra sarkan referans ile bırakılmış olacaksınız. Bu referansın kullanılması Tanımsız Davranış olacaktır.

Ancak, teknik olarak, bir referans-to-olmayan const resmi argüman için geçici geçmek mümkün amacıyla, sadece bu gibi küçük bir yardımcı tanımlayın:

template< class Type > 
auto temp_ref(Type&& o) 
    -> Type& 
{ return o; } 

Ardından aramak ör foo(temp_ref(Whatever())), ancak bu geçici sürenin ömrünün tam anlamıyla ifade edildiğini unutmayın.

+0

C++ 11 kullanıyorsanız, akış hareketli olmalıdır. – 0x499602D2

+0

Gerçekten de kötü düşünülmüş mü? Hiçbir şey yükleyici fonksiyonun referansı saklayacağını söylemez. Sadece veri yüklemek ve daha sonra onu silmek için kullandığı sürece, iyi olurdu? – Tobias

+0

@Tobias: Evet, kullanım geçici ömür içinde ise, hepsi sorun yok. :) –

-2

Yeni oluşturulmuş bir nesneye işaretçiyi geçmek işe yarayacaktır.

Loader(istream * pstream) 
{ 
    try 
    { 
     // ...... 

     delete pstream; 
     throw; 
    } 
    catch(...) 
    {  
     delete pstream;     
    } 
} 

Container(): 
mLoader(new ifstream("path/file.txt", ios::binary)) 
{ 
} 
+1

Bu, gerçekleşmesini bekleyen iğrenç bir kaynak sızıntısı! –

+0

Yığın ayrılan bir nesnenin adresini ilettiğinizde çökme gibi. – Tobias

+1

@Tobias VE zorunlu yedek bellek ayırma. –

İlgili konular