Since std::istream can't be moved (protected function), I was trying to wrap the std::istream so that I can build my code upon customized stream factory.
So far I have tried inheriting directly from std::istream like this:
class IStream : public std::istream{
public:
// template <typename T>
IStream(std::istringstream&& rhs) : std::istream(std::move(rhs)){
this->rdbuf(rhs.rdbuf());
rhs.istream::rdbuf(NULL);
}
IStream(IStream&& rhs) : std::istream(std::move(rhs)){
this->rdbuf(rhs.rdbuf());
rhs.rdbuf(NULL);
}
};
But it causes a segmentation fault (any insights on the reason would be appreciated), so I move on to some "safer-looking" method.
Here is the code I currently use:
#include <iostream>
#include <sstream>
#include <istream>
#include <string>
#include <memory>
#include <cassert>
using namespace std;
class IStream {
public:
IStream(const IStream& rhs) = delete;
template <typename T>
IStream(T& rhs) : shared_(rhs) {
std::cout << "called IStream(T&)" << std::endl;
}
// assume strict order between member construct for now
template <typename T>
IStream(T&& rhs) : owned_{std::make_unique<T>(std::move(rhs))}, shared_(*owned_) {
std::cout << "called IStream(T&&)" << std::endl;
}
IStream(IStream&& rhs) : owned_(std::move(rhs.owned_)), shared_(*owned_) {
assert(rhs.owned_.get() == nullptr); // failed
std::cout << "called IStream(IStream&&)" << std::endl;
}
std::istream& get() {
return shared_;
}
~IStream() {
std::cout << "called ~IStream with " << (owned_.get()!=nullptr) << std::endl;
}
private:
std::unique_ptr<std::istream> owned_;
std::istream& shared_;
};
IStream&& wrap() {
return IStream(istringstream{"test"});
}
int main(void) {
IStream is(wrap());
char buf[10];
memset(buf, 0, sizeof(char) * 10);
is.get().getline(buf, 10);
std::cout << std::string(buf) << std::endl;
return 0;
}
Sad thing is this code still won't work, and I found that assertion at IStream::IStream(IStream&&)
failed.
Output:
called IStream(T&&)
called ~IStream with 1
Assertion failed: rhs.owned_.get() == nullptr, file .\tmp.cpp, line 23
Which leads to wierd phenomenon where unique_ptr is not null after moved.
I am using MSVC compiler btw.
You cannot sanely do what you want.
As I understand it, you want some sort of object that is as indistinguishable from a ::std::istream
as possible, but has move semantics so that it will be automatically destroyed after it's no longer needed.
The primary useful attribute of anything that can be referred to as an ::std::istream
is that it is derived from ::std::istream
, and since it is ::std::istream
that can't be moved, nothing derived from it can be moved either.
So, you're left with the next best thing, a ::std::unique_ptr
to your ::std::istream
thing. This means you'll have to use *
all the time and it will be ugly. Oh, well.
No amount of cleverness will allow you to create any kind of wrapper that is simultaneously moveable, and derived from ::std::istream
so that it works with all the nice existing library functions that expect that. Nor can you make something that acts in any reasonable way like a reference without that thing actually being a reference.
BTW, when you construct a unique_ptr
you can provide a custom deleter if you're actually pointing at something like ::std::cin
that you don't want to delete. You can make the custom deleter simply do nothing in that case. The custom deleter will be moved right along with the pointer when you move your unique_ptr
around.
This function returns a dangling reference:
IStream&& wrap() {
return IStream(istringstream{"test"});
}
The temporary object is destroyed when the function returns. Instead change the function to return by value, IStream wrap() {
.
Also, shared_(*owned_)
leads to a dangling reference because that refers to the memory location where the currently-owned object resides, even if that object is destroyed and the unique_ptr is later changed to own a different object.
It would be a good idea to get rid of shared_
, and just call owned_.get()
as needed.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.