8

Given that strstream has the following constructor:

strstream( char* s, int n, std::ios_base::openmode mode);

I was wondering whether I can use the buffer underlying a standard string directly, in "read-only" mode of course to avoid weird side-effects from buffer reallocation:

std::string buffer("Dummy Data");
std::strstream ss(
  const_cast<char *>(buffer.data()), buffer.length(), std::ios_base::in);

std::string other;
ss >> other;
std::cout << other << std::endl;

To my surprise, the code above ends up making other an empty string. In the documentation there is an example where a C-array is used as a static buffer for strstream, so I'm wondering what's the reason it cannot use the contents of the std::string buffer?

Note: I can't use std::stringstream because the platform in question has a VS implementation that is limited to 4GB size as discussed here


UPDATE:

I see that using std::ios_base::app (as in the example) pretty much makes my code work. The biggest problem now (according to the comments I'm getting) is that strstream is long deprecated. Maybe there's something in boost iostreams that could help but idk much about that library.

Lorah Attkins
  • 5,331
  • 3
  • 29
  • 63
  • 1
    With file sizes like that I'd start looking into memory mapping the file and read from those. There are platform indepenent libraries for that. – Pepijn Kramer May 31 '23 at 13:19
  • 3
    `strstream` was deprecated 25 years ago, you really shouldn't be using it – Alan Birtles May 31 '23 at 13:22
  • @AlanBirtles Is there another alternative to `std::stringstream` ? The code I'm working with uses streams to serialize data (e.g. `myStream << delimiter << current_data[i] << ...`) and then flushes those streams to disk. The content is already "in memory" so I can't see how the suggestion to memory map a file would work for me, unless I use that (the memory mapped file) as my buffer and check if similar syntax exists (I mean similar to `stream << content`) – Lorah Attkins May 31 '23 at 13:32
  • 1
    This is explicitly marked as C++11, but just for completeness: C++23 std::spanstream is what you would want to use: https://stackoverflow.com/questions/67924325/how-will-stdspanstream-usually-be-used-in-c – Quxflux May 31 '23 at 13:42
  • 2
    @LorahAttkins Not entirely following your requirements, but why not write your own `std::streambuf` derived class. Then it can do whatever you want – john May 31 '23 at 13:54

1 Answers1

3

Instead of using strstream that was deprecated in C++98, and given that you can't use its standard recommended replacement which is stringstream due to the mentioned 4GB limitation in your compiler, you can use Boost's bufferstream as an alternative like this:

#include <iostream>
#include <boost/interprocess/streams/bufferstream.hpp>

namespace bi = boost::interprocess;

int main()
{
    std::string buffer("Dummy Data");

    bi::bufferstream ss(&buffer[0], buffer.size());

    std::string other;
    ss >> other;
    std::cout << other << std::endl;

    return 0;
}

This class seems to be header only, so no need to compile boost. In any case, if using Visual Studio, you can use vcpkg to easily install boost.

NOTE: As mentioned in Peppin's comment on the question, if your data originates from a file, it would be a better approach instead of reading it entirely into memory to just use memory-mapped files. There is a great example of how this is done in this answer.

vvv444
  • 2,764
  • 1
  • 14
  • 25
  • That's a great answer because the library also contains cross platform utilities for file mapping, which according to one of the comments should be an available fallback for really large datasets – Lorah Attkins May 31 '23 at 15:12
  • @LorahAttkins yep, that comment is extremely right. If your data comes from a file, no point in reading it entirely to RAM. I just tried answering your question in the narrow sense. But I can provide answer with file mapping as well if you like. – vvv444 May 31 '23 at 16:27
  • Went into a rabbit-hole with this because I ignored `bufferstream` only works with static buffers yet allows using `operator<<` to populate a default constructed instance, i.e. one without a buffer (causing UB). Ended up using `vectorstream` for streams populated on the fly and `bufferstream` to "avoid copying existing buffers. Btw I reinstated the c++11 tag, because that is the language standard I'm targeting. If I had no standard requirement I could use `std::spanstream` which brings no extra dependencies. – Lorah Attkins Jun 01 '23 at 12:36