Obtenir un std::ostream soit à partir de std::cout ou std::ofstream(fichier)

comment lier un std::ostreamstd::cout ou d'un std::ofstream objet, dépendant d'une certaine condition de programme? Bien que ceci ne soit pas valable pour de nombreuses raisons, je voudrais réaliser quelque chose qui est sémantiquement équivalent à ce qui suit:

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

j'ai vu quelques exemples qui ne sont pas d'exception-sûr, comme celui de 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;
}

personne Ne sait mieux, exception-safe solution?

40
demandé sur Frank Krueger 2008-12-14 23:41:19

4 réponses

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

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

std::ostream out(buf);

qui associe le streambuf sous-jacent soit de cout ou le flux de fichier de sortie à out. Après cela, vous pouvez écrire à "sortir" et il va finir dans la bonne destination. Si vous voulez juste que tout va std::cout va dans un fichier, vous pouvez aswell n'

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

cette seconde méthode a l'inconvénient qu'elle n'est pas exceptionnellement sûre. Vous voulez peut-être écrire une classe qui fait cela en utilisant 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;
}

maintenant, quoi qu'il arrive, std:: la goutte est dans état de propreté.

55
répondu Johannes Schaub - litb 2008-12-14 21:17:40

C'est l'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 a abordé cette question dans l'article Commutation de Flux (le Gourou de la Semaine).

23
répondu Tom 2008-12-14 20:48:12
std::ofstream of;
std::ostream& out = condition ? std::cout : of.open(filename);
10
répondu Tony Clifton 2011-04-02 05:16:51

étant novice en C++, Je ne sais pas si c'est sans danger d'exception, mais voici comment je le fais habituellement:

std::ostream& output = (condition)?*(new std::ofstream(filename)):std::cout;
0
répondu user32849 2017-11-29 16:42:36