2008-12-14 162 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;