Swapping a stringstream for cout - c++

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

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.

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.

Related

How to move std::ostringstream's underlying string object?

#include <sstream>
#include <string>
using namespace std;
template<typename T>
string ToString(const T& obj)
{
ostringstream oss;
oss << obj;
//
// oss will never be used again, so I should
// MOVE its underlying string.
//
// However, below will COPY, rather than MOVE,
// oss' underlying string object!
//
return oss.str();
}
How to move std::ostringstream's underlying string object?
The standard says that std::ostringstream::str() returns a copy.
One way to avoid this copy is to implement another std::streambuf derived-class that exposes the string buffer directly. Boost.IOStreams makes this pretty trivial:
#include <boost/iostreams/stream_buffer.hpp>
#include <iostream>
#include <string>
namespace io = boost::iostreams;
struct StringSink
{
std::string string;
using char_type = char;
using category = io::sink_tag;
std::streamsize write(char const* s, std::streamsize n) {
string.append(s, n);
return n;
}
};
template<typename T>
std::string ToString(T const& obj) {
io::stream_buffer<StringSink> buffer{{}};
std::ostream stream(&buffer);
stream << obj;
stream.flush();
return std::move(buffer->string); // <--- Access the string buffer directly here and move it.
}
int main() {
std::cout << ToString(3.14) << '\n';
}
Since C++20 you can.
std::move(oss).str()

Unordered_map using pointer address as key

I'm trying to create a map with a custom key, which is an object's pointer address, as mentioned.
I need the address because for now it's the only relevant way to compare between two objects.
from what i understood, the proper way of doing this is by using const char* as key
here is the typedef :
typedef __gnu_cxx::unordered_map<const char*, std::string> TargetsTags;
I'm a bit confused about the following:
how do I create the operator() ?
This is what i used for std::string:
namespace __gnu_cxx {
template<>
struct hash<std::string>
{
hash<const char*> h;
size_t operator()(const std::string &s) const
{
return h(s.c_str());
};
};
}
What about const char*?
And is this the correct way of doing this?
The working example using c++11:
#include <iostream>
#include <unordered_map>
#include <string>
#include <functional>
using namespace std;
class myhash {
public:
size_t operator() (const char *val) const {
return std::hash<std::string>()(val);
}
};
class myequal {
public:
bool operator()(const char *val1, const char *val2) const{
return std::string(val1) == std::string(val2);
}
};
int main() {
std::unordered_map<const char*, string, myhash, myequal> mymap;
mymap["abc"] = "abcd";
mymap["cba"] = "dcba";
std::cout << mymap["abc"] << std::endl;
return 0;
}

Boost Variant with base class causes 'C1060 compiler is out of heap space'

I'm hoping someone here has a workaround for this. This code compiles fine on gcc, and VS2010 SP1 (Debug x32, Release x32, Debug x64), but fails for 64 bit Release builds with a fatal error C1060: compiler is out of heap space. I'm using Boost 1.52
#include "stdafx.h"
#include <boost/variant.hpp>
#include <string>
#include <vector>
#include <map>
typedef boost::make_recursive_variant<
boost::blank,
std::string,
int,
double,
std::vector<std::vector<int> >,
std::vector<std::vector<double> >,
std::vector<std::vector<std::string> >,
std::map<std::string, std::vector<std::string> >,
std::map<std::string, std::vector<double> >,
std::map<std::string, std::vector<int> >,
std::map<std::string,boost::recursive_variant_>
>::type InfoHolder2;
class Test
{
InfoHolder2 test;
};
class Test3
{};
class Test4
{};
template <class T>
class Base
{
public:
Base(){};
virtual std::string Foo(const T& val, const std::string& header = "") const = 0;
virtual T Bar(const std::string& buffer, size_t offset = 0) const = 0;
};
template <class Payload, class iArchive, class oArchive>
class TestSer : Base<Payload>
{
public:
TestSer():Base()
{ }
virtual std::string Foo(const Payload& holder,const std::string& header = "") const
{
return "";
}
virtual Payload Bar( const std::string& buffer, size_t offset = 0) const
{
Payload retval;
return retval;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
new TestSer<Test, Test3, Test4>();
return 0;
}
This fails every time. If I reduce the number of elements the variant can handle I can get it to compile, but that isn't really preferred as this works nicely for me. If I change the class to the version below, it works. Does anyone have any ideas for workarounds?
template <class Payload, class iArchive, class oArchive>
class TestSer
{
public:
TestSer()
{ }
std::string Foo(const Payload& holder,const std::string& header = "") const
{
return "";
}
Payload Bar( const std::string& buffer, size_t offset = 0) const
{
Payload retval;
return retval;
}
};

how to convert single-byte string to wide string in c++?

I know the encoding and that the input string is 100% single byte, no fancy encodings like utf etc. And all I want is to convert it to wchar_t* or wstring basing on a known encoding. What functions to use ? btowc() and then loop ? Maybe string objects have something useful in them. There are lot of examples but all are for "multibyte" or fancy loops with btowc() that only show how to display output on screen that indeed this function is working, I haven't seen any serious example how to deal with buffers in such situation, is always wide char 2x larger than single char string ?
Try this template. It served me very well.
(author unknown)
/* string2wstring.h */
#pragma once
#include <string>
#include <vector>
#include <locale>
#include <functional>
#include <iostream>
// Put this class in your personal toolbox...
template<class E,
class T = std::char_traits<E>,
class A = std::allocator<E> >
class Widen : public std::unary_function<
const std::string&, std::basic_string<E, T, A> >
{
std::locale loc_;
const std::ctype<E>* pCType_;
// No copy-constructor, no assignment operator...
Widen(const Widen&);
Widen& operator= (const Widen&);
public:
// Constructor...
Widen(const std::locale& loc = std::locale()) : loc_(loc)
{
#if defined(_MSC_VER) && (_MSC_VER < 1300) // VC++ 6.0...
using namespace std;
pCType_ = &_USE(loc, ctype<E> );
#else
pCType_ = &std::use_facet<std::ctype<E> >(loc);
#endif
}
// Conversion...
std::basic_string<E, T, A> operator() (const std::string& str) const
{
typename std::basic_string<E, T, A>::size_type srcLen =
str.length();
const char* pSrcBeg = str.c_str();
std::vector<E> tmp(srcLen);
pCType_->widen(pSrcBeg, pSrcBeg + srcLen, &tmp[0]);
return std::basic_string<E, T, A>(&tmp[0], srcLen);
}
};
// How to use it...
int main()
{
Widen<wchar_t> to_wstring;
std::string s = "my test string";
std::wstring w = to_wstring(s);
std::wcout << w << L"\n";
}

How can I compose output streams, so output goes multiple places at once?

I'd like to compose two (or more) streams into one. My goal is that any output directed to cout, cerr, and clog also be outputted into a file, along with the original stream. (For when things are logged to the console, for example. After closing, I'd like to still be able to go back and view the output.)
I was thinking of doing something like this:
class stream_compose : public streambuf, private boost::noncopyable
{
public:
// take two streams, save them in stream_holder,
// this set their buffers to `this`.
stream_compose;
// implement the streambuf interface, routing to both
// ...
private:
// saves the streambuf of an ios class,
// upon destruction restores it, provides
// accessor to saved stream
class stream_holder;
stream_holder mStreamA;
stream_holder mStreamB;
};
Which seems straight-forward enough. The call in main then would be something like:
// anything that goes to cout goes to both cout and the file
stream_compose coutToFile(std::cout, theFile);
// and so on
I also looked at boost::iostreams, but didn't see anything related.
Are there any other better/simpler ways to accomplish this?
You do have the right design—if you want to do this purely within the stdlib.
One thing: instead of teeing to each streambuf on every output, implement it to use the same put area as one of the streambufs it's given, and copy to the others on overflow and sync. This will minimize virtual calls, which is one of the goals of how streambufs work.
Alternatively, and if you want to only handle stdout & stderr (which is common), run your program through the standard Unix tee program (or the equivalent on your platform), either by doing it yourself when invoking the program, or within the program by forking, setting up the streams as appropriate, etc.
Edit: You got me thinking, and I should know how to get this right. Here's my first approximation. (When this breaks, you get to keep both pieces.)
#ifndef INCLUDE_GUARD_A629F54A136C49C9938CB33EF8EDE676
#define INCLUDE_GUARD_A629F54A136C49C9938CB33EF8EDE676
#include <cassert>
#include <cstring>
#include <streambuf>
#include <map>
#include <vector>
template<class CharT, class Traits=std::char_traits<CharT> >
struct basic_streamtee : std::basic_streambuf<CharT, Traits> {
typedef std::basic_ios<CharT, Traits> Stream;
typedef std::basic_streambuf<CharT, Traits> StreamBuf;
typedef typename StreamBuf::char_type char_type;
typedef typename StreamBuf::traits_type traits_type;
typedef typename StreamBuf::int_type int_type;
typedef typename StreamBuf::pos_type pos_type;
typedef typename StreamBuf::off_type off_type;
basic_streamtee() : _key_buf(0) {}
basic_streamtee(Stream& a, Stream& b) : _key_buf(0) {
this->pubimbue(a.rdbuf()->getloc());
_set_key_buf(a.rdbuf());
insert(a);
insert(b);
}
~basic_streamtee() {
sync();
for (typename std::map<Stream*, StreamBuf*>::iterator i = _bufs.begin();
i != _bufs.end();
++i)
{
StreamBuf* old = i->first->rdbuf(i->second);
if (old != this) {
old->pubsync();
}
}
}
// add this functionality?
// streambufs would be unconnected with a stream
// easy to do by changing _bufs to a multimap
// and using null pointers for the keys
//void insert(StreamBuf* buf);
//void remove(StreamBuf* buf);
void insert(Stream& s) {
sync();
if (!_bufs.count(&s)) {
if (!_key_buf) {
_set_key_buf(s.rdbuf());
}
_bufs[&s] = s.rdbuf(this);
}
}
void remove(Stream& s) {
sync();
typename std::map<Stream*, StreamBuf*>::iterator i = _bufs.find(&s);
if (i != _bufs.end()) {
StreamBuf* old = i->second;
i->first->rdbuf(i->second);
_bufs.erase(i);
if (old == _key_buf) {
_set_key_buf(_bufs.empty() ? 0 : _bufs.begin()->second);
}
}
}
private:
basic_streamtee(basic_streamtee const&); // not defined
basic_streamtee& operator=(basic_streamtee const&); // not defined
StreamBuf* _key_buf;
std::map<Stream*, StreamBuf*> _bufs;
void _set_key_buf(StreamBuf* p) {
//NOTE: does not sync, requires synced already
_key_buf = p;
_update_put_area();
}
void _update_put_area() {
//NOTE: does not sync, requires synced already
if (!_key_buf) {
this->setp(0, 0);
}
else {
this->setp((_key_buf->*&basic_streamtee::pbase)(),
(_key_buf->*&basic_streamtee::epptr)());
}
}
#define FOREACH_BUF(var) \
for (typename std::map<Stream*, StreamBuf*>::iterator var = _bufs.begin(); \
var != _bufs.end(); ++var)
// 27.5.2.4.1 Locales
virtual void imbue(std::locale const& loc) {
FOREACH_BUF(iter) {
iter->second->pubimbue(loc);
}
}
// 27.5.2.4.2 Buffer management and positioning
//virtual StreamBuf* setbuf(char_type* s, std::streamsize n); // not required
//virtual pos_type seekoff(off_type off, std::ios_base::seekdir way,
// std::ios_base::openmode which); // not required
//virtual pos_type seekpos(pos_type sp, std::ios_base::openmode which); // not required
virtual int sync() {
if (!_key_buf) {
return -1;
}
char_type* data = this->pbase();
std::streamsize n = this->pptr() - data;
(_key_buf->*&basic_streamtee::pbump)(n);
FOREACH_BUF(iter) {
StreamBuf* buf = iter->second;
if (buf != _key_buf) {
buf->sputn(data, n); //BUG: ignores put errors
buf->pubsync(); //BUG: ignroes errors
}
}
_key_buf->pubsync(); //BUG: ignores errors
_update_put_area();
return 0;
}
// 27.5.2.4.3 Get area
// ignore input completely, teeing doesn't make sense
//virtual std::streamsize showmanyc();
//virtual std::streamsize xsgetn(char_type* s, std::streamsize n);
//virtual int_type underflow();
//virtual int_type uflow();
// 27.5.2.4.4 Putback
// ignore input completely, teeing doesn't make sense
//virtual int_type pbackfail(int_type c);
// 27.5.2.4.5 Put area
virtual std::streamsize xsputn(char_type const* s, std::streamsize n) {
assert(n >= 0);
if (!_key_buf) {
return 0;
}
// available room in put area? delay sync if so
if (this->epptr() - this->pptr() < n) {
sync();
}
// enough room now?
if (this->epptr() - this->pptr() >= n) {
std::memcpy(this->pptr(), s, n);
this->pbump(n);
}
else {
FOREACH_BUF(iter) {
iter->second->sputn(s, n);
//BUG: ignores put errors
}
_update_put_area();
}
return n;
}
virtual int_type overflow(int_type c) {
bool const c_is_eof = traits_type::eq_int_type(c, traits_type::eof());
int_type const success = c_is_eof ? traits_type::not_eof(c) : c;
sync();
if (!c_is_eof) {
char_type cc = traits_type::to_char_type(c);
xsputn(&cc, 1);
//BUG: ignores put errors
}
return success;
}
#undef FOREACH_BUF
};
typedef basic_streamtee<char> streamtee;
typedef basic_streamtee<wchar_t> wstreamtee;
#endif
Now, this test is far from complete, but it seems to work:
#include "streamtee.hpp"
#include <cassert>
#include <iostream>
#include <sstream>
int main() {
using namespace std;
{
ostringstream a, b;
streamtee tee(a, b);
a << 42;
assert(a.str() == "42");
assert(b.str() == "42");
}
{
ostringstream a, b;
streamtee tee(cout, a);
tee.insert(b);
a << 42 << '\n';
assert(a.str() == "42\n");
assert(b.str() == "42\n");
}
return 0;
}
Put it together with a file:
#include "streamtee.hpp"
#include <iostream>
#include <fstream>
struct FileTee {
FileTee(std::ostream& stream, char const* filename)
: file(filename), buf(file, stream)
{}
std::ofstream file;
streamtee buf;
};
int main() {
using namespace std;
FileTee out(cout, "stdout.txt");
FileTee err(clog, "stderr.txt");
streambuf* old_cerr = cerr.rdbuf(&err.buf);
cout << "stdout\n";
clog << "stderr\n";
cerr.rdbuf(old_cerr);
// watch exception safety
return 0;
}
You mention having not found anything in Boost.IOStreams. Did you consider tee_device?
I would write a custom stream buffer that just forwards data to the buffers of all your linked streams.
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <functional>
class ComposeStream: public std::ostream
{
struct ComposeBuffer: public std::streambuf
{
void addBuffer(std::streambuf* buf)
{
bufs.push_back(buf);
}
virtual int overflow(int c)
{
std::for_each(bufs.begin(),bufs.end(),std::bind2nd(std::mem_fun(&std::streambuf::sputc),c));
return c;
}
private:
std::vector<std::streambuf*> bufs;
};
ComposeBuffer myBuffer;
public:
ComposeStream()
:std::ostream(NULL)
{
std::ostream::rdbuf(&myBuffer);
}
void linkStream(std::ostream& out)
{
out.flush();
myBuffer.addBuffer(out.rdbuf());
}
};
int main()
{
ComposeStream out;
out.linkStream(std::cout);
out << "To std::cout\n";
out.linkStream(std::clog);
out << "To: std::cout and std::clog\n";
std::ofstream file("Plop");
out.linkStream(file);
out << "To all three locations\n";
}