I tried to hack into unique_ptr
's deleter, but without compromising construct by right value (we can't override deleter since it's associated with the right value). So I decided to try deriving from unique_ptr
, here is my code.
using OStreamPtr = std::unique_ptr<std::ostream>;
class MockOStreamPtr : public OStreamPtr {
public:
MockOStreamPtr(OStreamPtr&& rhs, MockOutputSystem* sys) : OStreamPtr(std::move(rhs)), sys_(sys) {}
MockOStreamPtr(std::ostream* p, MockOutputSystem* sys) : OStreamPtr(p), sys_(sys) {}
~MockOStreamPtr() {
std::cout << "~MockOStreamPtr" << std::endl;
if (sys_) {
std::cout << get()->good() << std::endl; // this failed already
// sys_->manage(*this);
}
}
protected:
MockOutputSystem* sys_ = nullptr;
};
MSVC gives me an SEH exception on accessing ostream
pointer during destruction, which I can't understand at all.
compact test case:
#include <iostream>
#include <sstream>
#include <istream>
#include <string>
#include <memory>
#include <cassert>
using namespace std;
using OStreamPtr = std::unique_ptr<std::ostream>;
class MockOutputSystem {
public:
template <typename T>
static OStreamPtr MakeStream(T&& rhs) {
return std::make_unique<T>(std::move(rhs));
}
OStreamPtr fopen(const std::string& file);
};
class MockOStreamPtr : public OStreamPtr {
public:
MockOStreamPtr(OStreamPtr&& rhs, MockOutputSystem* sys) : OStreamPtr(std::move(rhs)), sys_(sys) {}
MockOStreamPtr(std::ostream* p, MockOutputSystem* sys) : OStreamPtr(p), sys_(sys) {}
~MockOStreamPtr() {
std::cout << "~MockOStreamPtr" << std::endl;
if (sys_) {
std::cout << get()->good() << std::endl; // this failed already
// sys_->manage(*this);
}
}
protected:
MockOutputSystem* sys_ = nullptr;
};
OStreamPtr MockOutputSystem::fopen(const std::string& file) {
auto s = std::ostringstream();
s << file << ":" ;
return MockOStreamPtr(std::move(MakeStream(std::move(s))), this);
}
int main(void) {
MockOutputSystem sys;
OStreamPtr s(sys.fopen("test_file.b"));
(*s) << "hello world";
s.release(); // failed here
}