我一直在尝试使用C ++,我遇到了一个我不知道如何解决的问题。
基本上,我发现你不能复制流(见Why copying stringstream is not allowed?),这也适用于“包裹”它们的对象。例如:
这会导致错误C2249:
'std :: basic_ios< _Elem,_Traits> :: operator =':虚拟基地'std :: basic_ios< _Elem,_Traits>'
中声明的私有成员的无法访问路径
所以我的问题是:我怎样才能(最好轻松)复制具有* stream类型数据成员的对象?
完整的示例代码:
#include <iostream>
#include <string>
#include <sstream>
class TestStream
{
public:
std::stringstream str;
};
int main()
{
TestStream test;
TestStream test2;
test = test2;
system("pause");
return 0;
}
提前致谢。
更新
我已成功解决了这个问题,感谢下面的答案。我所做的是声明流对象一次,然后使用包装器对象中的指针(例如,TestStream)简单地引用它们。具有私有拷贝构造函数的所有其他对象也是如此。
答案 0 :(得分:5)
不允许您复制流的原因是it doesn't make sense to copy a stream。如果你解释一下你想要做什么,那肯定有办法做到这一点。如果您想要复制一大块数据,请使用字符串。但是流更像是连接而不是字符串。
答案 1 :(得分:2)
This article提供了实现目标的方法。但请注意有趣的总结:
总之,创建流的副本并非易事,而且应该只是 如果你真的需要一个流对象的副本,那就完成了。在许多情况下, 使用引用或指针来流对象更合适 相反,或者在两个流之间共享流缓冲区。
答案 2 :(得分:1)
当然,您必须自己编写复制构造函数和复制赋值运算符。
接下来,您必须确定您希望副本具有哪些语义。所以:
TestStream test;
TestStream test2;
test2 << "foo"
test = test2;
test << "bar";
test2.str.str(); // should this be "foo" or "foobar" ?
如果你想要一个浅拷贝("foobar"
),那么你需要在TestStream
的多个实例之间共享stringstream对象,可能最好使用shared_ptr
。
如果您需要深层副本("foo"
),那么您可以像这样复制:
TestStream(const TestStream &rhs) : str(rhs.str.str()) {}
或者使用您链接到的问题中的一个变体。
当你拍摄副本时,它会覆盖你正在写中的字符串流。如果你正处于阅读的中间,或者你正在写作但由于使用seekp
而你可能没有写到最后,那么你需要捕获当前的读/写位置以及stringstream中的数据,您使用tellg/tellp
。
您可能还希望复制整个流的格式状态,依此类推,这是copyfmt
的作用,甚至错误标记(rdstate
- copyfmt
也只留下它们)。
答案 3 :(得分:0)
你可以做两件事,都涉及小心谁拥有这个对象:
存储对流的引用,并确保只要这些类的对象存在,对象就不会超出范围。
复制指针,并确保仅在最后一个类完成指向的流对象时删除。
两者都是等价的,虽然我个人更喜欢参考方法。
答案 4 :(得分:0)
为了测试c ++中各种写操作的性能,这里有一个代码,可以在你的机器上编译并使用以下几种方法测试写入操作是否有缓冲:
#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();
}