Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
416 views
in Technique[技术] by (71.8m points)

iostream - How to translate C file pointers into generic C++ streams?

Consider the following C code:

void openFile(const char *mode, char *filename, FILE **fileptr)
{
  ...
  *fileptr = fopen(filename, mode);
  ...
}

FILE *logstream;
if (LOG_FILE_ENABLED)
{
  openFile("w", "mylogfile.txt", logstream);
}
else
{
  logstream = stderr;
}

fprintf(logstream, "[DEBUG] Some debug message...
");
fclose(logstream);

I am attempting to translate this to idiomatic C++. How can I overload openFile() such that it takes a std::ofstream, but keep logstream stream-agnostic? I was assuming it would be something like this:

void openFile(const char *mode, char *filename, std::ofstream &ofs)
{
  ...
  ofs.open(filename);
  ...
}

std::ostream logstream;
if (LOG_FILE_ENABLED)
{
  logstream = std::ofstream();
  openFile("w", "mylogfile.txt", logstream);
}
else
{
  logstream = std::cerr;
}

logstream << "[DEBUG] Some debug message..." << std::endl;
logstream.close();

However this is apparently wildly incorrect - you can't even initialize a plain std::ostream like that. How should I handle this - preferably while avoiding the use of raw pointers?

question from:https://stackoverflow.com/questions/65941918/how-to-translate-c-file-pointers-into-generic-c-streams

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

C++ stream library has pretty ancient design. Nevertheless - its basic idea is that ostream or istream are just wrapper objects over stream-buffers.

So you might try something like in this code:

std::ostream get_log(bool str) {
    if (str) return std::ostream(new std::stringbuf());
     // else
    std::filebuf* f = new std::filebuf();
    f->open("log", std::ios_base::out);
    return std::ostream(f);
}

But, as I mentioned, this is very ancient design - so no RAII - this buffer is not owned by stream - you would need to delete it by yourself:

int main() {
    std::ostream log = get_log(true);
    log << "aaa";
    std::cout << static_cast<std::stringbuf&>(*log.rdbuf()).str();
    
    delete log.rdbuf(); // (!)
}

So this is not very usable.

So my final advice - use smart pointer over ostream - like this:

std::unique_ptr<std::ostream> get_log(bool str) {
    if (str) return new std::ostringstream();
    std::ofstream* f = new std::ofstream();
    f->open("log", std::ios_base::out);
    return f;
}

int main() {
    auto log = get_log(true);
    *log << "aaa";
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...