L Holness
L Holness

Reputation: 21

How to cast to a shared_ptr<std::ofstream> from std::shared_ptr<boost::iostreams::stream<boost::iostreams::null_sink>>

I have a member that is a shared_ptr<ofstream>.

In a specific case, I want to suppress the output, and making the stream a boost::iostreams::stream<boost::iostreams::null_sink>. Should do what I want.

I would prefer to avoid the ofstream(nullptr) suggested in this thread, it doesn't compile when wrapped in make_shared().

I'm open to other null ofstream shared_ptr suggestions, but it needs to be cross platform.

Initializing it with an output (non suppressed) works:

InputReader::InputReader(std::string filepath2, std::string filepathmain){
    this->thestreamstruct.themainWriter = std::move(std::make_shared<std::ofstream>(filepathmain.c_str()));
}

In the suppressed initializer, I declare the null sink stream shared_ptr instead of initializing the ofstream, and then want to cast this to an ofstream and assign it to the member:

InputReader::InputReader(std::string filepath2, Model* amodel){
    std::shared_ptr<boost::iostreams::stream<boost::iostreams::null_sink>> nullOstream = std::make_shared<boost::iostreams::stream<boost::iostreams::null_sink>>((boost::iostreams::null_sink()));
    std::shared_ptr<std::ofstream> nullost = std::move(std::dynamic_pointer_cast<std::ofstream>(nullOstream)); 
    this->thestreamstruct.themainWriter = nullost; 
}

This fails because there's no direct cast between std::ofstream and the boost stream.

But I can assign an ofstream ref as the boost null sink??

boost::iostreams::stream<boost::iostreams::null_sink> nullout { boost::iostreams::null_sink{} };
std::ostream& out = nullout;

This is fine, so there must be the underlying ofstream somewhere? I just don't know how to get it wrapped up into a shared_ptr.

Upvotes: 1

Views: 230

Answers (1)

sehe
sehe

Reputation: 392833

Taking some pains to get life-time correct without leaking the buffer:

Live On Coliru

#include <boost/iostreams/device/null.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <memory>

using std::filesystem::path;
using sofstream = std::shared_ptr<std::ofstream>;

sofstream make_null() {
    struct both {
        boost::iostreams::stream_buffer<boost::iostreams::null_sink> b{{}};
        std::ofstream                                                ofs;
    };
    auto s = std::make_shared<both>();
    static_cast<std::ios&>(s->ofs).rdbuf(&s->b);
    return sofstream(s, &s->ofs);
}

sofstream make(path p) { return std::make_shared<std::ofstream>(p); }

int main() {
for (auto ss : { make_null(), make("test.txt") }) {
        *ss << "hello world\n";
        assert(ss->good());
        *ss << "bye world\n";
        assert(ss->good());
    }
}

I personally think this whole approach might be to clever by half and you should use std::ostream& instead of std::ofstream& anyways. (e.g. http://coliru.stacked-crooked.com/a/333cc9871c5e977b)

Upvotes: 0

Related Questions