简体   繁体   English

从 std::cout 或 std::ofstream(file) 获取 std::ostream

[英]Obtain a std::ostream either from std::cout or std::ofstream(file)

how do I bind a std::ostream to either std::cout or to an std::ofstream object, depending on a certain program condition?如何根据特定程序条件将std::ostream绑定到std::coutstd::ofstream对象? Although this invalid for many reasons, I would like to achieve something that is semantically equivalent to the following:尽管由于多种原因这无效,但我想实现在语义上等同于以下内容的内容:

std::ostream out = condition ? &std::cout : std::ofstream(filename);

I've seen some examples that are not exception-safe, such as one from http://www2.roguewave.com/support/docs/sourcepro/edition9/html/stdlibug/34-2.html :我见过一些不是异常安全的示例,例如来自http://www2.roguewave.com/support/docs/sourcepro/edition9/html/stdlibug/34-2.html 的示例:

int main(int argc, char *argv[])
{
  std::ostream* fp;                                           //1
  if (argc > 1)
     fp = new std::ofstream(argv[1]);                         //2
  else
     fp = &std::cout                                          //3

  *fp << "Hello world!" << std::endl;                         //4
  if (fp!=&std::cout) 
     delete fp;
}

Does anyone know a better, exception-safe solution?有谁知道更好的、异常安全的解决方案?

std::streambuf * buf;
std::ofstream of;

if(!condition) {
    of.open("file.txt");
    buf = of.rdbuf();
} else {
    buf = std::cout.rdbuf();
}

std::ostream out(buf);

That associates the underlying streambuf of either cout or the output file stream to out.这将 cout 或输出文件流的底层流缓冲与 out 相关联。 After that you can write to "out" and it will end up in the right destination.之后,您可以写入“out”,它将最终到达正确的目的地。 If you just want that everything going to std::cout goes into a file, you can aswell do如果你只是希望所有进入std::cout都进入一个文件,你也可以这样做

std::ofstream file("file.txt");
std::streambuf * old = std::cout.rdbuf(file.rdbuf());
// do here output to std::cout
std::cout.rdbuf(old); // restore

This second method has the drawback that it's not exception safe.第二种方法的缺点是它不是异常安全的。 You possibly want to write a class that does this using RAII:您可能想编写一个使用 RAII 执行此操作的类:

struct opiped {
    opiped(std::streambuf * buf, std::ostream & os)
    :os(os), old_buf(os.rdbuf(buf)) { }
    ~opiped() { os.rdbuf(old_buf); }

    std::ostream& os;
    std::streambuf * old_buf;
};

int main() {
    // or: std::filebuf of; 
    //     of.open("file.txt", std::ios_base::out);
    std::ofstream of("file.txt");
    {
        // or: opiped raii(&of, std::cout);
        opiped raii(of.rdbuf(), std::cout);
        std::cout << "going into file" << std::endl;
    }
    std::cout << "going on screen" << std::endl;
}

Now, whatever happens, std::cout is in clean state.现在,无论发生什么, std::cout 都处于干净状态。

This is exception-safe:这是异常安全的:

void process(std::ostream &os);

int main(int argc, char *argv[]) {
    std::ostream* fp = &cout;
    std::ofstream fout;
    if (argc > 1) {
        fout.open(argv[1]);
        fp = &fout;
    }
    process(*fp);
}

Edit: Herb Sutter has addressed this in the article Switching Streams (Guru of the Week) .编辑:Herb Sutter 在文章Switching Streams (Guru of the Week) 中已经解决了这个问题。

std::ofstream of;
std::ostream& out = condition ? std::cout : of.open(filename);

Referencing from this post .引用自这篇文章

You can apply a similar approach.您可以应用类似的方法。

struct noop {
    void operator()(...) const {}
};
std::shared_ptr<std::ostream> of;
if (condition) {
    of.reset(new std::ofstream(filename, std::ofstream::out));
} else {
    of.reset(&std::cout, noop());
}

作为 C++ 的新手,我不知道这是否是异常安全的,但我通常这样做:

std::ostream& output = (condition)?*(new std::ofstream(filename)):std::cout;

The following simple code works for me:以下简单代码对我有用:

int main(int argc, char const *argv[]){   

    std::ofstream outF;
    if (argc > 1)
    {
        outF = std::ofstream(argv[1], std::ofstream::out); 
    }

    std::ostream& os = (argc > 1)? outF : std::cout;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM