C++复制流对象

发布于 2024-12-12 01:55:21 字数 995 浏览 0 评论 0原文

我一直在尝试C++,并且遇到了一个我不知道如何解决的问题。

基本上,我发现您无法复制流(请参阅 为什么不能复制 stringstream允许吗?),这也适用于“包裹”它们的对象。例如:

  • 我创建一个具有 stringstream 类型的数据成员的类。
  • 我创建了这个类的一个对象。
  • 我尝试复制该对象,例如“TestObj t1; TestObj t2; t1 = t2;”

这会导致错误 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)中的指针简单地引用它们。对于具有私有复制构造函数的所有其他对象也是如此。

I've been experimenting with C++, and I've come across a problem that I don't know how to solve.

Basically, I've discovered that you can't copy streams (see Why copying stringstream is not allowed?), and that also applies for objects that 'wrap' them. For example:

  • I create a class with a data member of type stringstream.
  • I create an object of this class.
  • I attempt to copy the object, eg "TestObj t1; TestObj t2; t1 = t2;"

This causes the error C2249:

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

So my question is: how can I (preferably easily) copy objects that have data members of type *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've managed to solve this problem thanks the answers below. What I have done is declare the stream objects once and then simply reference them using pointers in the wrapper objects (eg, TestStream). The same goes for all other objects that have private copy constructors.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

栀梦 2024-12-19 01:55:21

不允许您复制流的原因是 它不复制流是有意义的。如果你解释了你想要做什么,那么肯定有办法做到这一点。如果您想要可以复制的数据块,请使用字符串。但流更像是连接而不是字符串。

The reason you are not allowed to copy a stream is that it doesn't make sense to copy a stream. If you explain what it is that you are trying to do, there's certainly a way to do it. If you want a chunk of data you can copy, use a string. But a stream is more like a connection than a string.

叫嚣ゝ 2024-12-19 01:55:21

本文提供了实现此目的的方法。但请注意有趣的总结:

总之,创建流的副本并不简单,应该只
如果您确实需要流对象的副本,请完成此操作
。在很多情况下,
使用流对象的引用或指针更合适
相反,或者在两个流之间共享流缓冲区。

This article provides ways to do it. Note however the interesting summary:

In summary, creating a copy of a stream is not trivial and should only
be done if you really need a copy of a stream object
. In many cases,
it is more appropriate to use references or pointers to stream objects
instead, or to share a stream buffer between two streams.

十六岁半 2024-12-19 01:55:21

当然你必须自己编写复制构造函数和复制赋值运算符。

接下来,您必须决定您希望副本具有什么语义。因此:

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,您可能没有写到最后,那么您需要捕获当前读/写位置以及字符串流中的数据,您可以使用tellg/tellp来完成此操作。

您可能还想复制流的格式状态等,这就是 copyfmt 的作用,甚至是错误标志 (rdstate -- copyfmt< /code> 让他们独自一人)。

Certainly you have to write the copy constructor and copy assignment operator yourself.

Next, you have to decide what semantics you would like the copy to have. So:

TestStream test;
TestStream test2;
test2 << "foo"
test = test2;
test << "bar";

test2.str.str(); // should this be "foo" or "foobar" ?

If you want a shallow copy, ("foobar") then you need to share the stringstream object between multiple instances of TestStream, probably best to use a shared_ptr for that.

If you want a deep copy ("foo"), then you could copy like this:

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

Or use one of the variants in the question you link to.

That covers a stringstream to which you're in the middle of writing when you take the copy. If you're in the middle of reading from it, or if you're writing but you might not be writing to the end because of use of seekp, then you need to capture the current read/write positions as well as the data in the stringstream, which you do with tellg/tellp.

You might also want to copy across the stream's format state, and so on, which is what copyfmt does, and even the error flags (rdstate -- copyfmt leaves them alone).

〗斷ホ乔殘χμё〖 2024-12-19 01:55:21

您可以做两件事,两者都涉及小心谁拥有该对象:

  1. 存储对流的引用,并确保只要您的这些类存在,该对象就不会超出范围。< /p>

  2. 复制指针,并确保仅在最后一个类完成指向的流对象时才删除。

两者是等效的,尽管我个人更喜欢参考方法。

There are two things you can do, both involve being careful about who owns the object:

  1. Store a reference to a stream, and make sure the object does not go out of scope as long as these classes of yours are around.

  2. copy the pointers around, and be sure to delete only when the last of your classes is done with the stream object pointed to.

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

完美的未来在梦里 2024-12-19 01:55:21

为了测试 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();
}

To test the performance of various write operations in c++ here is a code which compiles on your machine and tests write operations with and without buffering with several methods:

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();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文