0
#include <fstream> 
#include <vector>
#include <iostream>

int main()
{
    bool bWriteConsole = true;
    std::streambuf *buf;
    std::ofstream outfile;

    if (bWriteConsole)
        buf = std::cout.rdbuf();
    else
    {
        outfile.open("./hello.bin", std::ofstream::binary | std::ofstream::out);
        buf = outfile.rdbuf();
    }

    std::ostream outstream(buf);
    std::vector<char> m_tableBuffer;
    double dValue = 1.2345;
    const void* dBytes = &dValue;
    std::copy(static_cast<const char *>(dBytes), static_cast<const char *>(dBytes) + sizeof(double), std::back_inserter(m_tableBuffer));

    outstream.write((char*)m_tableBuffer.data(), m_tableBuffer.size());

    if (!bWriteConsole)
        outfile.close();
    else
        std::cout << std::flush;

    return 0;
}

I need to add a function to my existing application so that it can output the binary stream to stdout instead of file. The prototype is shown above.

Question> Is there any issue with this implementation? Is there an elegant solution without considering RAII?

Thank you

== Updated based on comments from luk32

void function2()
{
    bool bWriteConsole = true;
    std::ofstream outfile;

    if (!bWriteConsole)
        outfile.open("./hello.bin", std::ofstream::binary | std::ofstream::out);

    std::vector<char> m_tableBuffer;
    double dValue = 1.2345;
    const void* dBytes = &dValue;
    std::copy(static_cast<const char *>(dBytes), static_cast<const char *>(dBytes) + sizeof(double), std::back_inserter(m_tableBuffer));

    if (!bWriteConsole)
    {
        outfile.write((char*)m_tableBuffer.data(), m_tableBuffer.size());
        outfile.close();
    }
    else
    {
        std::cout.write((char*)m_tableBuffer.data(), m_tableBuffer.size());
        std::cout.flush();
    }
}
q0987
  • 34,938
  • 69
  • 242
  • 387
  • Why not have the funciton simply take `std::ostream&` and pass in either a `std::ofstream`, or `std::cout`? – Angew is no longer proud of SO Oct 11 '18 at 15:29
  • What's wrong with simply using `std::ostream::write(reinterpret_cast(T&), sizeof T)`? You have no buffer and no copy, and no need for making a half-copy of `cout` by creating another `ostream` with same `rdbuf`. `cout` is an `ostream` already. Is there a reason you copy memory content into intermediary buffer? – luk32 Oct 11 '18 at 15:33
  • @luk32, for output directly to stdout, I have no reason to buffer the result. However, for output directly to file, I have to buffer the result in memory first, then flush all contents to file in the end. – q0987 Oct 11 '18 at 15:36
  • @luk32, I was reading this post https://stackoverflow.com/questions/366955/obtain-a-stdostream-either-from-stdcout-or-stdofstreamfile – q0987 Oct 11 '18 at 15:37
  • Why? There is essentially no difference between `ofstream` in `cout`. The question you linked has this line "*Although this invalid for many reasons, I would like to achieve [...]*". I tend to agree with the sentiment. It might be an XY problem. `ofstream` and `cout`(because it's `ostream`) are both buffered. They both provide `flush`. – luk32 Oct 11 '18 at 15:38
  • @luk32, I made a change based on your comments. Please check it out – q0987 Oct 11 '18 at 15:44

1 Answers1

1

My version would something more akin to this:

#include <iostream>
#include <fstream>

void function2(bool bWriteConsole)
{
    std::ofstream outfile;

    if (!bWriteConsole)
        outfile.open("./hello.bin", std::ofstream::binary | std::ofstream::out);

    double dValue = 1.2345;

    // writing out
    std::ostream& out = bWriteConsole ? std::cout : outfile;
    out.write(reinterpret_cast<char*>(&dValue), sizeof dValue);
    out.flush();
}

Writing code is 2 lines, 3 if you really want to flush. outfile.close() would flush as well, so there is no harm in flushing unconditionally versus your approach. File will get closed when outfile goes out of scope so it doesn't have to be written unless you really want to manually close the file before some further processing. Here it's superfluous (RAII goodness comes into play here).

Aaand maybe refactor writing:

template<typename T>
void dump(T val, std::ostream& out ) {
    out.write(reinterpret_cast<char*>(&val), sizeof val);
    out.flush();
}

void function2(bool bWriteConsole)
{
    std::ofstream outfile;

    if (!bWriteConsole)
        outfile.open("./hello.bin", std::ofstream::binary | std::ofstream::out);

    double dValue = 1.2345;
    dump(dValue, bWriteConsole ? std::cout : outfile);
    // writing out
}
luk32
  • 15,812
  • 38
  • 62