C ++ copy stream object

I experimented with C ++ and I ran into a problem that I do not know how to solve.

Basically, I found that you cannot copy streams (see Why copying a stringstream is not allowed? ), And this also applies to objects that 'wrap them. For example:

  • I am creating a class with a data member of type stringstream.
  • I am creating an object of this class.
  • I am trying to copy an object like "TestObj t1; TestObj t2; t1 = t2;"

This causes error C2249:

'std :: basic_ios <_Elem, _Traits> :: operator =': there is no accessible path to the private member declared in the virtual database 'std :: basic_ios <_Elem, _Traits>'

So my question is: how can I (preferably easily) copy objects that have data members like * stream?

Full example code:

#include <iostream> #include <string> #include <sstream> class TestStream { public: std::stringstream str; }; int main() { TestStream test; TestStream test2; test = test2; system("pause"); return 0; } 

Thanks in advance.

UPDATE

I managed to solve this problem thanks to the answers below. What I did is declare the stream objects once, and then just reference them using pointers in wrapper objects (like TestStream). The same applies to all other objects that have private copy constructors.

+7
source share
5 answers

The reason you are not allowed to copy the stream is because it does not make sense to copy the stream . If you explain exactly what you are trying to do, this is definitely a way to do it. If you need a piece of data that you can copy, use the line. But a stream is more like a join than a string.

+4
source

This article describes how to do it. Please note, however, an interesting summary:

Thus, making a copy of the stream is not trivial and should if you really need a copy of the stream object . In many cases, it is more advisable to use references or pointers for streams of objects instead, or to share a stream buffer between two streams.

+1
source

Of course, you need to write the copy constructor itself and the copy assignment operator.

Then you need to decide what kind of semantics you need a copy. So:

 TestStream test; TestStream test2; test2 << "foo" test = test2; test << "bar"; test2.str.str(); // should this be "foo" or "foobar" ? 

If you need a shallow copy, ( "foobar" ), then you need to split the stringstream object between multiple instances of TestStream , perhaps shared_ptr best used for this.

If you need a deep copy ( "foo" ), you can copy like this:

 TestStream(const TestStream &rhs) : str(rhs.str.str()) {} 

Or use one of the options in the question you are referring to.

This covers the line to which you are in the middle of the letter when you take a copy. If you are in the middle of reading from it or if you are writing, but you cannot write to the end due to the use of seekp , then you need to fix the current read / write positions, as well as the data in the string stream that you execute with tellg/tellp .

You can also copy content in stream format, etc., which is what copyfmt does, and even error flags ( rdstate - copyfmt leave them alone).

+1
source

There are two things you can do: both must be careful about who owns the object:

  • Keep a reference to the stream and make sure the object does not go out of scope while these classes are around.

  • copy the pointers and be sure to delete them only when the last of your classes is executed with the specified stream object.

Both are equivalent, although I personally prefer the reference approach.

0
source

To test the performance of various write operations in C ++, here is the code that compiles on your computer and tests write operations with and without buffering in several ways:

Link

 #include <stdio.h> #include <cstring> #include <iostream> #include <fstream> #include <chrono> #define TOCOUT(output) \ if(!outputToCout) { \ buf = output##_t.rdbuf(); \ } else { \ buf = std::cout.rdbuf(); \ } \ std::ostream output(buf); void fstreamBufferTest(){ const bool outputToCout = true; const unsigned int multiplyStep = 1<<2; const unsigned int startLength = 1<<2; const unsigned int stopLength = 1<<24; const unsigned int writeNTimes = 1; // Averaging over some many times! const unsigned int fileLength = 1<< 30; //104857600=100mb, 314572800=300mb , 1<< 30 =1GB std::string add = "1000.txt"; unsigned int loops, restBytes; std::streambuf * buf; std::ofstream output1_t("FStreamTest-FstreamBuffering-OwnBufferSet-"+add); TOCOUT(output1); output1 << "#Buffer Length \tTimeToWrite \tWriteSpeed [mb/s]" << std::endl; std::ofstream output2_t("FStreamTest-ManualBuffering-StdStreamBuffer-"+add); TOCOUT(output2); output2 << "#Buffer Length \tTimeToWrite \tWriteSpeed [mb/s]" << std::endl; std::ofstream output3_t("FStreamTest-ManualBuffering-NoInternalStreamBuffer-"+add); TOCOUT(output3); output3 << "#Buffer Length \tTimeToWrite \tWriteSpeed [mb/s]" << std::endl; std::ofstream output4_t("FStreamTest-NoManualBuffering-NoInternalStreamBuffer-"+add); TOCOUT(output4); output4 << "#Buffer Length \tTimeToWrite\tWriteSpeed [mb/s]" << std::endl; std::ofstream output5_t("FStreamTest-NoManualBuffering-StdStreamBuffer-"+add); TOCOUT(output5); output5 << "#Buffer Length \tTimeToWrite \tWriteSpeed [mb/s]" << std::endl; // To Cout typedef std::chrono::duration<double> fsec; typedef std::chrono::high_resolution_clock Clock; // Test Data for the Buffer bool removeFile = true; char value = 1; char *testData = new char[fileLength]; // Just Garbage 1GB!! std::memset(testData,value,fileLength); // Preallocate file; if(!removeFile){ std::fstream stream; stream.open("test.dat", std::ios::binary | std::ios::trunc | std::ios::out); for(int i = 0; i < writeNTimes; i++){ stream.write(testData, fileLength ); } stream.close(); }else{ if( remove( "test.dat" ) == 0){ std::cout << "File deleted at start!" << std::endl; } } for(unsigned int bufL = startLength; bufL <= stopLength; bufL = bufL * multiplyStep){ // First Test with Fstream Buffering! { std::cout << "Doing test: FStream Buffering: " << bufL <<std::endl; char * buffer = new char[bufL]; //open Stream std::fstream stream; stream.rdbuf()->pubsetbuf(buffer, bufL); stream.open("test.dat", std::ios::binary | std::ios::trunc | std::ios::out); // Write whole 1gb file! we have fstream buffering the stuff auto t1 = Clock::now(); for(int i = 0; i < writeNTimes; i++){ stream.write(testData, fileLength ); } stream.close(); auto t2 = Clock::now(); //Calculate timing fsec time = (t2 - t1) / writeNTimes; output1 << bufL << "\t" << time.count() <<"\t" << (fileLength/time.count()) / (1024*1024) << std::endl; delete buffer; if(removeFile){ if( remove( "test.dat" ) != 0){ std::cerr << "File not deleted" << std::endl; }; } } // Second Test with Manual Buffering! { std::cout << "Doing test: Manual Buffering: " << bufL <<std::endl; // Calculate the loops to write fileLength loops = fileLength / bufL; restBytes = fileLength % bufL; //open Stream std::fstream stream; stream.open("test.dat", std::ios::binary | std::ios::trunc | std::ios::out); // TODO stream buf -> 0 // Write 1GB File in loops of bufL auto t1 = Clock::now(); for(int i = 0; i < writeNTimes; i++){ for(int i = 0; i < loops; i++){ stream.write(testData, bufL ); } stream.write(testData, restBytes ); } stream.close(); auto t2 = Clock::now(); //Calculate timing fsec time = (t2 - t1) / writeNTimes; output2 << bufL << "\t" << time.count() <<"\t" << (fileLength/time.count()) / (1024*1024) << std::endl; if(removeFile){ if( remove( "test.dat" ) != 0){ std::cerr << "File not deleted" << std::endl; }; } } // Second Test with Manual Buffering! { std::cout << "Doing test: Manual Buffering (no internal stream buffer): " << bufL <<std::endl; // Calculate the loops to write fileLength loops = fileLength / bufL; restBytes = fileLength % bufL; //open Stream std::fstream stream; stream.open("test.dat", std::ios::binary | std::ios::trunc | std::ios::out); stream.rdbuf()->pubsetbuf(0, 0); // Write 1GB File in loops of bufL auto t1 = Clock::now(); for(int i = 0; i < writeNTimes; i++){ for(int i = 0; i < loops; i++){ stream.write(testData, bufL ); } stream.write(testData, restBytes ); } stream.close(); auto t2 = Clock::now(); //Calculate timing fsec time = (t2 - t1) / writeNTimes; output3 << bufL << "\t" << time.count() <<"\t" << (fileLength/time.count()) / (1024*1024) << std::endl; if(removeFile){ if( remove( "test.dat" ) != 0){ std::cerr << "File not deleted" << std::endl; }; } } { std::cout << "Doing test: No manual Buffering (no internal stream buffer): " << bufL <<std::endl; // Calculate the loops to write fileLength loops = fileLength / bufL; restBytes = fileLength % bufL; //open Stream std::fstream stream; stream.open("test.dat", std::ios::binary | std::ios::trunc | std::ios::out); stream.rdbuf()->pubsetbuf(0, 0); // Write 1GB File in loops of bufL auto t1 = Clock::now(); for(int i = 0; i < writeNTimes; i++){ stream.write(testData, fileLength ); } stream.close(); auto t2 = Clock::now(); //Calculate timing fsec time = (t2 - t1) / writeNTimes; output4 << bufL << "\t" << time.count() <<"\t" << (fileLength/time.count()) / (1024*1024) << std::endl; if(removeFile){ if( remove( "test.dat" ) != 0){ std::cerr << "File not deleted" << std::endl; }; } } { std::cout << "Doing test: No manual Buffering (std stream buffer): " << bufL <<std::endl; //Calculate the loops to write fileLength loops = fileLength / bufL; restBytes = fileLength % bufL; //open Stream std::fstream stream; stream.open("test.dat", std::ios::binary | std::ios::trunc | std::ios::out); // Write 1GB File in loops of bufL auto t1 = Clock::now(); for(int i = 0; i < writeNTimes; i++){ stream.write(testData, fileLength ); } stream.close(); auto t2 = Clock::now(); //Calculate timing fsec time = (t2 - t1)/ writeNTimes; output5 << bufL << "\t" << time.count() <<"\t" << (fileLength/time.count()) / (1024*1024) << std::endl; if(removeFile){ if( remove( "test.dat" ) != 0){ std::cerr << "File not deleted" << std::endl; }; } } } } int main() { fstreamBufferTest(); } 
0
source

All Articles