有没有一个好的习惯用法来处理替代输出流

Is there a good idiom to deal with alternative output streams?

本文关键字:处理 输出流 惯用法 习惯 有一个      更新时间:2023-10-16

我想写一个简单的程序,根据传递给它的选项,可执行文件将输出打印到屏幕或文件中。程序很简单。

#include<iostream>
int main(int argc, char* argv[]){
    ... process options...
    std::ostream& out = ... // maybe std::cout, maybe a *new* std::ofstream;
    out << "contentn";
}

是否有一个好的习惯用法可以在运行时交替引用std::cout或文件流

我试着用指针,但太可怕了。我无法避免使用指针(更不用说以后需要更多难看的代码来删除指针)。

#include<iostream>
#include<ofstream>
int main(int argc, char* argv[]){
    std::string file = argc>1?argv[1]:"";
    std::clog << "file: " << file << 'n';
    // if there is no argument it will print to screen
    std::ostream* out = (file=="")?&std::cout:(new std::ofstream(file)); // horrible code
    *out << "content" << std::endl;
    if(out != &std::cout) delete out;
}

我不知道,也许C++流的某些特性允许这样做。也许我必须使用某种类型的擦除。我认为,问题是std::cout已经存在的东西(是全局的),但std::ofstream是必须创建的东西。

我设法使用了open并避免了指针,但它仍然很难看:

int main(int argc, char* argv[]){
    std::string file = argc>1?argv[1]:"";
    std::clog << "file: " << file << 'n';
    std::ofstream ofs; 
    if(file != "") ofs.open(file); 
    std::ostream& out = (file=="")?std::cout:ofs;
    out << "content" << std::endl;
}

我更喜欢使用安装了合适流缓冲区的流。以下是直接输出到文件或std::cout:的一种方式

#include <iostream>
#include <fstream>
int main(int ac, char* av) {
    std::ofstream ofs;
    if (1 < ac) {
       ofs.open(av[1]);
       // handle errors opening the file here
    }
    std::ostream os(file? file.rdbuf(): std::cout.rdbuf());
    // use os ...
}

太多了。

#include <iostream>
#include <fstream>
int main(int argc, char* argv[]) {
    std::ofstream ofs(argc > 1 ? argv[1] : "");
    std::ostream& os = ofs.is_open() ? ofs : std::cout;
    // use os ...
}

所需流的运行时绑定将非常需要看起来像您已经拥有的。

关于指针问题,请确保您可以稍微清理一下。。。也许是这样的?这是假设您只想在参数存在的情况下创建ofstream

int main(int argc, char* argv[]){ 
    std::string file = argc > 1 ? argv[1] : "";
    std::clog << "file: " << file << 'n';
    // if there is no argument it will print to screen
    std::unique_ptr<std::ostream> fp;
    if (file == "")
        fp = std::make_unique<std::ofstream>(file);
    std::ostream& out = (fp && fp->is_open()) ? std::cout : *fp; // not so horrible code
    out << "content" << std::endl;
}

如果不需要动态对象,最简单的可能是列出这个;

int main(int argc, char* argv[]){
    std::string filename = (argc > 1) ? argv[1] : "";
    std::ofstream file(filename);
    // if there is no argument (file) it will print to screen
    std::ostream& out = file.is_open() ? file : std::cout;
    out << "content" << std::endl;
}

我经常在命令行工具中使用这样的东西:

int main(int, char* argv[])
{
    std::string filename;
    // args processing ... set filename from command line if present
    if(argv[1])
        filename = argv[1];
    std::ofstream ofs;
    // if a filename was given try to open
    if(!filename.empty())
        ofs.open(filename);
    // bad ofs means tried to open but failed
    if(!ofs)
    {
        std::cerr << "Error opeing file: " << filename << 'n';
        return EXIT_FAILURE;
    }
    // Here either ofs is open or a filename was not provided (use std::cout)
    std::ostream& os = ofs.is_open() ? ofs : std::cout;
    // write to output
    os << "Some stuff" << 'n';
    return EXIT_SUCCESS;
}

您可以使用指向多态行为的流的共享指针:

#include <memory>
#include <fstream>
#include <sstream>
#include <iostream>
void nodelete(void*) {}
std::shared_ptr<std::ostream> out_screen_stream() { return std::shared_ptr<std::ostream>(&std::cout, nodelete); }
std::shared_ptr<std::ostream> out_file_stream() { return std::make_shared<std::ofstream>(); }
std::shared_ptr<std::ostream> out_string_stream() { return std::make_shared<std::ostringstream>(); }
int main ()
{
    std::shared_ptr<std::ostream> out;
    // case condition:
    out = out_screen_stream();
    out = out_file_stream();
    out = out_string_stream();
    *out << "content" << std::endl;
    return 0;
}

注意:std::shared_ptr允许管理不同的可能流,其中一些流不应该被删除(例如:std:∶cout)。

类似,但使用std::unique_ptr:

#include <memory>
#include <fstream>
#include <sstream>
#include <iostream>
class Deleter
{
    public:
    Deleter(bool use_delete = true) : use_delete(use_delete) {}
    template <typename T>
    void operator () (const T* p) {
        if(use_delete)
            delete p;
    }
    bool nodelete() const { return ! use_delete; }
    private:
    bool use_delete;
};
using unique_ostream_ptr = std::unique_ptr<std::ostream, Deleter>;
unique_ostream_ptr out_screen_stream() { return unique_ostream_ptr(&std::cout, false); }
unique_ostream_ptr out_file_stream() { return unique_ostream_ptr{ new std::ofstream }; }
unique_ostream_ptr out_string_stream() { return unique_ostream_ptr{ new std::ostringstream  }; }
int main ()
{
    unique_ostream_ptr out;
    // case condition:
    out = out_screen_stream();
    out = out_file_stream();
    out = out_string_stream();
    *out << "content" << std::endl;
    return 0;
}

也许是引用?

#include<iostream>
#include<ofstream>

int main(int argc, char* argv[])
{
    auto &out = std::cout;
    std::ofstream outFile;
    std::string fileName = argc>1?argv[1]:"";
    std::clog << "file: " << file << 'n';
    // if there is no argument it will print to screen
    if(!fileName.empty())
    {
        outFile.open(fileName);
        out = outFile;
    }
    out<<"one, one, two";
    return 0;
}