如何根据某个程序条件将a绑定std::ostream
到一个std::cout
或一个std::ofstream
对象?虽然这有多种原因无效,但我想实现在语义上等同于以下内容的东西:
std::ostream out = condition ? &std::cout : std::ofstream(filename);
我见过一些不例外的示例,例如来自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; }
有谁知道一个更好的,异常安全的解决方案?
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
都进入文件,你也可以这样做
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执行此操作的类:
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都处于干净状态.
这是例外安全的:
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在文章" 切换流"(本周的大师)中已经解决了这个问题.
std::ofstream of; std::ostream& out = condition ? std::cout : of.open(filename);