关于c ++:从std :: cout或std :: ofstream(file)获取std :: ostream

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

如何根据特定程序条件将std::ostream绑定到std::coutstd::ofstream对象? 尽管由于多种原因这是无效的,但我想实现在语义上等同于以下内容的内容:

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

我看到了一些异常安全的示例,例如http://www2.roguewave.com/support/docs/sourcepro/edition9/html/stdlibug/34-2.html中的示例:

1
2
3
4
5
6
7
8
9
10
11
12
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;
}

有谁知道更好的,异常安全的解决方案?


1
2
3
4
5
6
7
8
9
10
11
std::streambuf * buf;
std::ofstream of;

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

std::ostream out(buf);

这会将cout或输出文件流的基础streambuf关联到out。 之后,您可以写入" out",它将最终到达正确的目的地。 如果您只希望将要进入std::cout的所有内容都放入一个文件中,则可以执行

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

第二种方法的缺点是它不是异常安全的。 您可能想编写一个使用RAII执行此操作的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
}

现在,无论发生什么,std :: cout都处于干净状态。


这是异常安全的:

1
2
3
4
5
6
7
8
9
10
11
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);
}

编辑:Herb Sutter在文章切换流(本周专家)中解决了此问题。


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


从这篇文章引用。

您可以应用类似的方法。

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

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

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


以下简单代码对我有用:

1
2
3
4
5
6
7
8
9
10
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;
}