I created a custom istream derived from std::istream that uses a custom streambuf when the file is a zipped file and std::filebuf otherwise.
#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());
}
I am able to assign derived class unique_ptr to base class unique_ptr at one place
b_ = std::make_unique<gzipbuf>(path);
but not at the other
b_ = fb;
It says
candidate function not viable: no known conversion from 'unique_ptr<std::filebuf, default_delete<std::basic_filebuf<char>>>' to 'unique_ptr<std::basic_streambuf<char>, default_delete<std::basic_streambuf<char>>>' for 1st argument
operator=(unique_ptr&& __u) noexcept
Firstly, after this line
std::unique_ptr<std::filebuf> fb;
fb
doesn't actually point at anything, it is just an empty unique_ptr
so you are invoking undefined behaviour here:
fb->open(path.c_str(), std::ios::in);
To fix this just change the line to:
auto fb = std::make_unique<std::filebuf>();
Regarding the error you are getting, if this line were allowed
b_ = fb;
then afterwards both b_
and fb
would point at the same object. This is not allowed by unique_ptr
. A resource can be owned by one, and only one, unique_ptr
. One solution is to pass ownership from fb
to b_
using std::move
:
b_ = std::move(fb)
and then fb
no longer owns anything.
Personally, I like to initialize member variables in the constructor initializer list wherever possible and would extract out the creation of the streambuf
to a separate function in order to do so:
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;
}
Then the constructor of my_stream
can be:
my_stream::my_stream(const std::string &path) : std::istream(nullptr),
b_(createStream(path)) {
this->init(b_.get());
}
This happened to me, but it was because I forgot to inherit publicly :)
// Was:
class Derived: Base
{
};
// Should have been:
class Derived: public Base
{
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With