将派生 class unique_ptr 分配给基础 class unique_ptr
Assign derived class unique_ptr to base class unique_ptr
我创建了一个派生自 std::istream 的自定义 istream,当文件是压缩文件时使用自定义 streambuf,否则 std::filebuf。
#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());
}
我可以在一处
将派生 class unique_ptr 分配给基础 class unique_ptr
b_ = std::make_unique<gzipbuf>(path);
但不是在另一个
b_ = fb;
它说
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
首先,在这一行之后
std::unique_ptr<std::filebuf> fb;
fb
实际上并没有指向任何东西,它只是一个空的 unique_ptr
所以你在这里调用了未定义的行为:
fb->open(path.c_str(), std::ios::in);
要解决此问题,只需将行更改为:
auto fb = std::make_unique<std::filebuf>();
关于您收到的错误,如果允许此行
b_ = fb;
然后 b_
和 fb
将指向同一个对象。 unique_ptr
不允许这样做。一项资源只能由一个人拥有,unique_ptr
。一种解决方案是使用 std::move
:
将所有权从 fb
传递给 b_
b_ = std::move(fb)
然后 fb
不再拥有任何东西。
就个人而言,我喜欢尽可能在构造函数初始化列表中初始化成员变量,并将 streambuf
的创建提取到一个单独的函数中,以便这样做:
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;
}
那么my_stream
的构造函数可以是:
my_stream::my_stream(const std::string &path) : std::istream(nullptr),
b_(createStream(path)) {
this->init(b_.get());
}
我创建了一个派生自 std::istream 的自定义 istream,当文件是压缩文件时使用自定义 streambuf,否则 std::filebuf。
#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());
}
我可以在一处
将派生 class unique_ptr 分配给基础 class unique_ptrb_ = std::make_unique<gzipbuf>(path);
但不是在另一个
b_ = fb;
它说
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
首先,在这一行之后
std::unique_ptr<std::filebuf> fb;
fb
实际上并没有指向任何东西,它只是一个空的 unique_ptr
所以你在这里调用了未定义的行为:
fb->open(path.c_str(), std::ios::in);
要解决此问题,只需将行更改为:
auto fb = std::make_unique<std::filebuf>();
关于您收到的错误,如果允许此行
b_ = fb;
然后 b_
和 fb
将指向同一个对象。 unique_ptr
不允许这样做。一项资源只能由一个人拥有,unique_ptr
。一种解决方案是使用 std::move
:
fb
传递给 b_
b_ = std::move(fb)
然后 fb
不再拥有任何东西。
就个人而言,我喜欢尽可能在构造函数初始化列表中初始化成员变量,并将 streambuf
的创建提取到一个单独的函数中,以便这样做:
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;
}
那么my_stream
的构造函数可以是:
my_stream::my_stream(const std::string &path) : std::istream(nullptr),
b_(createStream(path)) {
this->init(b_.get());
}