Reputation: 1240
pubsetbuf member of std::stringbuf is not working at all in Visual Studio 2010!
The code:
char *FileData = ... ;
unsigned long long FileDataLen = ... ;
std::stringstream *SS = new std::stringstream(std::stringstream::in | std::stringstream::out);
SS->rdbuf()->pubsetbuf( FileData, (std::streamsize)FileDataLen );
pubsetbuf does nothing in Visual Studio!!!
Workaround #1:
std::stringstream *SS = new std::stringstream( std::string(FileData, (size_type)FileDataLen ) ),std::stringstream::in | std::stringstream::out);
Workaround #2:
SS->rdbuf()->sputn(FileData, (streamsize)FileDataLen);
But both of these workarounds produce unnecessary memory copying. I definitely need a working pubsetbuf member of std::stringbuf.
Upvotes: 3
Views: 2329
Reputation: 492
I recently encountered the same issue of setbuf not being implemented in Visual Studio 2017.
After some searching on Stack Overflow, I found a solution for an output stream that doesn't use copying of the buffer which I modified for an input stream. Here they are for reference.
Source: Setting the internal buffer used by a standard stream (pubsetbuf)
#include <streambuf> template <typename char_type> struct ostreambuf : public std::basic_streambuf<char_type, std::char_traits<char_type> > { ostreambuf(char_type* buffer, std::streamsize bufferLength) { // set the "put" pointer the start of the buffer and record it's length. setp(buffer, buffer + bufferLength); } };
Source: Internal buffer used by standard input stream (pubsetbuf)
#include <streambuf> template <typename char_type> struct istreambuf : public basic_streambuf<char_type, char_traits<char_type>> { istreambuf(char_type* buffer, streamsize buffer_length) { // Set the "get" pointer to the start of the buffer, the next item, and record its length. this->setg(buffer, buffer, buffer + buffer_length); } }; int main() { ifstream infile(FILENAME, ifstream::binary); // Read entire file into buffer. infile.seekg(0, ios::end); streampos length = infile.tellg(); infile.seekg(0, ios::beg); vector<char> buffer(length); //char* buffer = new char[length]; infile.read(&buffer[0], length); infile.close(); // Create buffer and point local_stream to it. istreambuf<char> istream_buffer(&buffer[0], length); istream local_stream(&istream_buffer); string str1; while (local_stream >> str1) { . . . } }
Upvotes: 0
Reputation: 21
I see the same thing. I'm working on scenarios that definitely can't afford making unnecessary data copies. This seems to be somehow intentional as per comments in basic_streambuf class:
virtual basic_streambuf *__CLR_OR_THIS_CALL setbuf(_Elem *, streamsize)
{ // offer buffer to external agent (do nothing)
return (this);
}
Upvotes: 0
Reputation: 31
basic_ios.clear() If you need to change rdbuf, call this first or it'll fail to work.
std::ifstream file("file1.txt"); // file1.txt contains "Welcome!"
std::stringstream ss;
ss << file.rdbuf();
std::cout << ss.str() << std::endl;
Outputs "Welcome!".
Let's try again with a new file.
// Empty it
file.close();
ss.str("");
// New file
file.open("file2.txt"); // file2.txt contains "Goodbye!"
ss << file.rdbuf();
std::cout << ss.str() << std::endl;
Outputs nothing.
ss.clear();
ss << file.rdbuf();
std::cout << ss.str() << std::endl;
file.close();
Outputs "Goodbye!"
Upvotes: 3
Reputation: 47448
putsetbuf
only makes sense for fstream
(technically, for std::basic_filebuf
), where the buffer and the stream are two different things.
For stringstream
(technically, std::basic_stringbuf
) they are one and the same std::string.
If you need a stream that works on a string that's external to it, consider std::strstream
: or boost::iostreams::array_sink
Upvotes: 4