2016-06-16 6 views
2

Ich habe einen benutzerdefinierten istream erstellt, der von std :: istream abgeleitet wurde und einen benutzerdefinierten streambuf verwendet, wenn die Datei eine gezippte Datei und ansonsten std :: filebuf ist.Zuweisen der abgeleiteten Klasse unique_ptr zur Basisklasse unique_ptr

#mystream.h 
class my_stream: public istream { 
    public: 
    explicit my_stream(const std::string &path); 
    private:  
    std::unique_ptr<std::streambuf> b_; 
} 

#mystream.cpp 
my_stream::my_stream(const std::string &path) :std::istream(nullptr) { 
    if(path.substr(path.length()-6, path.length())==".gzip"){ 
     b_ = std::make_unique<gzipbuf>(path); //gzipbuf is derived from std::streambuf 
    } 
    else { 
     std::unique_ptr<std::filebuf> fb; 
     fb->open(path.c_str(), std::ios::in); 
     b_ = fb; 
    } 
    this->init(b_.get()); 
} 

Ich bin in der Lage abgeleiteten Klasse unique_ptr zu Basisklasse unique_ptr an einem Ort zuordnen

b_ = std::make_unique<gzipbuf>(path); 

aber nicht auf der anderen

b_ = fb; 

Es sagt Kandidat Funktion nicht lebensfähig: nein bekannte Konvertierung von 'unique_ptr' zu 'unique_ptr, default_delete' für das erste Argument operator = (unique_ptr & & __u) noexcept

+3

Sie müssen * Umzug * es: 'b = std :: move (fb);' denn hier kann immer nur sein, eine (keine Kopien). – Galik

Antwort

6

Zum einen nach dieser Zeile

std::unique_ptr<std::filebuf> fb; 

fb nicht wirklich auf etwas hinweisen, ist es nur ein leeres unique_ptr so dass Sie den Aufruf nicht definiertes Verhalten hier:

fb->open(path.c_str(), std::ios::in); 

Um dies zu beheben, ändern Sie einfach die Zeile wie folgt:

den Fehler In Bezug auf Sie bekommen, wenn diese Linie

erlaubt waren beide
b_ = fb; 

dann danach b_ und fb auf das gleiche Objekt zeigen würde. Dies ist nicht zulässig von unique_ptr. Eine Ressource kann nur einer sein: unique_ptr. Eine Lösung ist, das Eigentum zu übergeben fb-b_ mit std::move:

b_ = std::move(fb) 

und dann fb nicht mehr besitzen nichts.

Ich persönlich mag Membervariablen im Konstruktor Initialisiererliste, wo immer möglich, initialisieren und würde die Schaffung des streambuf in eine separate Funktion, um so zu tun, extrahieren:

std::unique_ptr<std::streambuf> createStream(const std::string &path) { 
    if(path.substr(path.length()-5, path.length())==".gzip"){ // I think you meant 5 here! 
     return std::make_unique<gzipbuf>(path); 
    } 
    auto fb = std::make_unique<std::filebuf>(); 
    fb->open(path.c_str(), std::ios::in); 
    return fb; 
} 

Dann wird der Konstruktor von my_stream sein kann:

my_stream::my_stream(const std::string &path) : std::istream(nullptr), 
    b_(createStream(path)) { 
    this->init(b_.get()); 
} 
+0

Danke! Das macht Sinn. – pikachu