2008-12-14 163 views
38

根据特定的程序条件,我如何将std::ostream绑定到std::coutstd::ofstream对象?虽然有很多原因无效,我想实现的东西,是语义上等效于以下内容:从std :: cout或std :: ofstream(文件)获取std :: ostream

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; 
} 

有谁知道更好的例外安全解决方案吗?

回答

52
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关联。之后,你可以写出“出”,它会在正确的目的地结束。如果你只是想一切要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; 
} 

现在,无论发生什么情况,标准::法院是干净的状态。

22

这是异常安全:

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); 
} 

编辑:香草萨特的文章Switching Streams (Guru of the Week)中已经解决了这一点。

+0

这似乎并不比任何更多的异常安全原始代码。 – Brian 2008-12-22 20:46:20

+0

是的。如果在处理(* fp <<“Hello World”<< std :: endl)时引发异常,则原始代码会发生内存泄漏。 – Tom 2008-12-23 03:58:42

+1

为什么这个答案得到我的投票是第一个答案打破了我的旧规则“不要惹别人的内部物体”。只是因为你**可以**取代rdbuf并不意味着你应该。 – 2011-02-28 11:06:50

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

作为一个新手,C++,我不知道这是否是异常安全的,但在这里是如何我通常做:

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