lundi 20 mai 2019

Trouble wrapping std::istream, unique_ptr not null after moved

Since std::istream can't be moved, 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 whould 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.

Aucun commentaire:

Enregistrer un commentaire