Swapping a stringstream for cout

和自甴很熟 提交于 2019-12-24 16:41:35

问题


With glibc's stdio, I can swap a memstream for stdout, thereby capturing the output of a piece of code compiled to output to stdout:

#include <stdio.h>

void swapfiles(FILE* f0, FILE* f1){ FILE tmp; tmp = *f0; *f0 = *f1; *f1 = tmp; }

void hw_c(){ puts("hello c world"); }

int c_capt(){
  FILE* my_memstream;
  char* buf  = NULL;
  size_t bufsiz = 0;

  if( (my_memstream = open_memstream(&buf, &bufsiz)) == NULL) return 1;

  FILE * oldstdout = stdout;

  swapfiles(stdout, my_memstream);
  hw_c();
  swapfiles(stdout, my_memstream);

  fclose(my_memstream);
  printf("Captured: %s\n", buf);
}

I'm curious if the same is possible for iostreams. My naive attempt won't compile:

#include <iostream>
#include <string>
#include <sstream>

void hw_cc(){ std::cout<<"hello c++ world\n"; }
int cc_capt(){
  using namespace std;

  stringstream ss;
  string capt;

  //std::swap(ss,cout); //<- the compiler doesn't like this
  hw_cc();
  //std::swap(ss,cout); 

  cout<<"Captured: "<<capt<<'\n';
}

int main(int argc, char** argv){
  c_capt();
  puts("---------------------------------");
  cc_capt();
  return 0;
}

回答1:


You can, but you don't swap the whole stream--just the stream buffer.

void cc_capt() {
    using namespace std;

    stringstream ss;

    auto orig = std::cout.rdbuf(ss.rdbuf());

    hw_cc();

    std::cout.rdbuf(orig);

    std::cout << "captured: " << ss.str() << "\n";
}

Note that in this case, we're not really using the stringstream itself at all, just the stringbuf it contains. If we wanted, we could just define a basic_stringbuf<char> and use that directly instead of defining a stringstream and then only use the stringbuf it contains.




回答2:


Based on Jerry's samples, I wrote a template which has one great advantage, it's safe (i.e. if an exception occurs, your buffer gets restored automatically.)

Use this way:

{
  ostream_to_buf<char> buf(std::cout);

  ... run code which `std::cout << "data"` ...

  std::string const output(buf.str());

  ... do something with `output` ...
}  // <-- here the buffer is restored

Here is the functional template which I think follows the STL pretty closely. The template is itself an std::stringbuf which inserts itself in the constructor. The destructor restores the original buffer so it is exception safe.

template<
      class CharT
    , class Traits = std::char_traits<CharT>
    , class Allocator = std::allocator<CharT>
>
class ostream_to_buf
    : public std::basic_stringbuf<CharT, Traits, Allocator>
{
public:
    typedef CharT                       char_type;
    typedef Traits                      traits_type;
    typedef typename Traits::int_type   int_type;
    typedef typename Traits::pos_type   pos_type;
    typedef typename Traits::off_type   off_type;
    typedef Allocator                   allocator_type;

    typedef std::basic_stringbuf<char_type, traits_type, allocator_type>    stringbuf_type;
    typedef std::basic_ostream<char_type, traits_type>                      stream_type;
    typedef std::basic_streambuf<char_type, traits_type>                    streambuf_type;
    typedef std::basic_string<char_type, traits_type, allocator_type>       string_type;

    ostream_to_buf<char_type, traits_type, allocator_type>(stream_type & out)
        : f_stream(out)
        , f_original(f_stream.rdbuf(this))
    {
    }

    ostream_to_buf<char_type, traits_type, allocator_type>(ostream_to_buf<char_type, traits_type, allocator_type> const & rhs) = delete;
    ostream_to_buf<char_type, traits_type, allocator_type> & operator = (ostream_to_buf<char_type, traits_type, allocator_type> const & rhs) = delete;

    ~ostream_to_buf()
    {
        f_stream.rdbuf(f_original);
    }

private:
    stream_type &       f_stream;
    streambuf_type *    f_original = nullptr;
};

The copy constructor and assignment operator are deleted because these do not work in this case.

You probably can make it work with C++11 or even C++03. I have C++14 but I don't think any of these require C++14.



来源:https://stackoverflow.com/questions/37758378/swapping-a-stringstream-for-cout

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!