Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ostream: class that outputs either on cout or on a file

Tags:

c++

ostream

I need to write a program that output either to the std::cout or to some file. I was reading this post to see how to do. However I would like to separate the management of the ostream from the main. So I was thinking to write a class, but I'm a bit confused about the design. I have in mind two solution

  1. (publicly) Subclass ostream: it this way I would have all method of ostream. However here the main problem would be the creator:

    class sw_ostream : public ostream {
       sw_ostream (cost char* filename) : ostream ( \\? ) {
       \\ ...
       }
    \\...
    }
    

because I should initialize ostream depending on filename, and apparently is impossible.

  1. Create a class having osteram as a member and overload operator<<.

I'm sure that there are other, more elegant solution to this problem. Which design would you suggest?

like image 669
MaPo Avatar asked Oct 19 '25 11:10

MaPo


1 Answers

I would try to split here the stream creation with the stream usage. std::ostream is already polymorphic, so as long as you pass a reference or pointer to the function that uses the stream, all good.

For the creation, I would go for creating the stream in the heap, as the post you linked to suggests. However, doing explicit memory management (raw new/delete) is dangerous, so I would use a smart pointer, like std::unique_ptr:

#include <fstream>
#include <memory>

struct ConditionalDeleter
{
    bool must_delete;
    void operator()(std::ostream* os) const { if (must_delete) delete os; }
};

using OstreamPtr = std::unique_ptr<std::ostream, ConditionalDeleter>;

OstreamPtr create_stream(bool to_file)
{
    if (to_file)
        return OstreamPtr { new std::ofstream {"myfile.txt"}, ConditionalDeleter {true} };
    else
        return OstreamPtr { &std::cout, ConditionalDeleter {false} };
}

void use_stream(std::ostream& os)
{
    os << "Hello world!" << std::endl;
}

int main()
{
    auto streamptr = create_stream(false);
    use_stream(*streamptr);
}

I've used a custom deleter with std::unique_ptr. The reason for that is: if we are using the file, I want the stream to be deleted; but std::cout is a global object, which we must not delete. The agreement here is that when your OstreamPtr gets destroyed, ConditionalDeleter::operator() will get called. *streamptr returns you a reference to your std::ostream, which you can use as you want.

Please note you need C++11 support to use this solution.

like image 135
anarthal Avatar answered Oct 21 '25 01:10

anarthal