Move the String Out of a Std::Ostringstream

Move the string out of a std::ostringstream

std::ostringstream offers no public interface to access its in-memory buffer unless it non-portably supports pubsetbuf (but even then your buffer is fixed-size, see cppreference example)

If you want to torture some string streams, you could access the buffer using the protected interface:

#include <iostream>
#include <sstream>
#include <vector>

struct my_stringbuf : std::stringbuf {
const char* my_str() const { return pbase(); } // pptr might be useful too
};

int main()
{
std::vector<float> v = {1.1, -3.4, 1/7.0};
my_stringbuf buf;
std::ostream ss(&buf);
for(unsigned int i=0; i < v.size(); ++i)
ss << v[i] << ' ';
ss << std::ends;
std::cout << buf.my_str() << '\n';
}

The standard C++ way of directly accessing an auto-resizing output stream buffer is offered by std::ostrstream, deprecated in C++98, but still standard C++14 and counting.

#include <iostream>
#include <strstream>
#include <vector>

int main()
{
std::vector<float> v = {1.1, -3.4, 1/7.0};
std::ostrstream ss;
for(unsigned int i=0; i < v.size(); ++i)
ss << v[i] << ' ';
ss << std::ends;
const char* buffer = ss.str(); // direct access!
std::cout << buffer << '\n';
ss.freeze(false); // abomination
}

However, I think the cleanest (and the fastest) solution is boost.karma

#include <iostream>
#include <string>
#include <vector>
#include <boost/spirit/include/karma.hpp>
namespace karma = boost::spirit::karma;
int main()
{
std::vector<float> v = {1.1, -3.4, 1/7.0};
std::string s;
karma::generate(back_inserter(s), karma::double_ % ' ', v);
std::cout << s << '\n'; // here's your string
}

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

Is there a way to std::move std::string into std::stringstream

Since C++20 you can move a string into a stringstream: cppreference


Old answer for pre-C++20:

I do not see a std::stringstream constructor accepting rvalue reference of std::string

That's right. Even the str setter doesn't utilize move semantics, so moving a string into stringstream is not supported (not in the current standard, but hopefully in the next one).

Is it legal to move the .str() member of a stringstream?

std::ostream::str indeed returns a copy of the internal string. So the move is legal, but it makes no sense as result.str() is an rvalue anyway and thus the std::move does nothing useful. If anything, it hinders RVO, so don't do it. (As @TartanLlama correctly pointed out in their comment, "Don't move the return value" holds true in general, not just when returning rvalues.)

In particular, the std::move does not affect the internal string object of the stream.

Move or swap a stringstream

This is a missing feature on GCC : see bug 54316 , it has been fixed (you can thank Jonathan Wakely) for the next versions (gcc 5)

Clang with libc++ compiles this code :

int main () {

std::stringstream stream("1234");

std::stringstream stream2 = std::move(std::stringstream("5678"));

return 0;
}

Live demo

And it also compiles the example with std::stringstream::swap

Redirect from a std::ostringstream to another std::ostringstream

You can reassign the associated buffers:

os2.rdbuf(os1.rdbuf());

That effectively aliases the ostream.

In fact, you can even construct ostream directly from a streambuffer pointer IIRC


Similarly, you can append the whole buffer to another stream without reassigning:

std::cout << mystringstream.rdbuf(); // prints the stringstream to console

remove char from stringstream and append some data

You can extract the string (with the str() member), remove the last char with std::string::erase and then reset the new string as buffer to the std::ostringstream.

However, a better solution would be to not insert the superfluous ',' in the first place, by doing something like that :

std::ostringstream douCoh;
const char* separator = "";

douCoh << '{';
for (size_t i = 0; i < dataSize; ++ i)
{
if (v[i].test)
{
douCoh << separator << i + 1;
separator = ",";
}
}
douCoh << '}';

How do I convert from stringstream to string in C++?

​​​​​​​

yourStringStream.str()


Related Topics



Leave a reply



Submit