2011-10-26 1 views
7

私はC++を試していましたが、解決方法がわからないという問題が出てきました。C++はストリームオブジェクトをコピーします

基本的に、ストリームをコピーできないことがわかりました(Why copying stringstream is not allowed?を参照)。また、それらを 'ラップする'オブジェクトにも適用されます。たとえば、次のようになります。

  • データメンバstringstreamのクラスを作成します。
  • 私はこのクラスのオブジェクトを作成します。
  • オブジェクトをコピーしようとしました(例: "TestObj t1; TestObj t2; t1 = t2;"

    'のstd :: basic_ios < _Elem、_Traits> ::演算子=':

これは、エラーC2249が発生した仮想ベース「のstd :: basic_ios <をで宣言されたプライベートメンバへのアクセスパスありません_Elem、_Traits>」

だから私の質問は:どのように私(好ましく簡単が)タイプ*ストリームのデータメンバを持つオブジェクトをコピーすることができますか?

完全なコード例:事前に

#include <iostream> 
#include <string> 
#include <sstream> 

class TestStream 
{ 
public: 
    std::stringstream str; 
}; 

int main() 
{ 
    TestStream test; 
    TestStream test2; 
    test = test2; 

    system("pause"); 
    return 0; 
} 

感謝。

UPDATE

私は以下のおかげで答え、この問題を解決するために管理してきました。私がやったことはストリームオブジェクトを一度宣言してから、単にラッパーオブジェクト(例えばTestStream)のポインタを使ってそれらを参照するだけです。プライベートコピーコンストラクタを持つ他のすべてのオブジェクトについても同様です。

+0

あなたがいるように見えるので、あなたの宿題、リンクされた質問をしました。なぜあなたはこの振る舞いを必要としますか?読み書き? –

答えて

0

あなたが行うことができる2つのものがありますが、両方のオブジェクトの所有者について気をつけながら巻き込む:

  1. ストアストリームへの参照を、オブジェクトがある限りスコープの外に出ていないことを確認してくださいこれらのクラスはあなたの周りにあります。

  2. ポインタをコピーして、最後のクラスがストリームオブジェクトを指しているときにのみ削除してください。

どちらも同等ですが、私は個人的に参考にしています。

+0

2位に入り、C++ 11対応のコンパイラを持っていれば、スマートポインタを使うことができます。このようなコンパイラを使用しない場合は、ブーストライブラリを使用するか、スマートポインタクラスを自分で書くことができます。 @Daroktharは同意した。 – Darokthar

+2

これは、 'boost :: shared_ptr'が適切である(そしていずれの選択肢に対しても望ましい)ケースです。 –

1

This articleは、それを行う方法を提供します。 は簡単ではありませんし、あなたが本当にストリームオブジェクトのコピーが必要な場合にのみ が行われるべきストリームのコピーを作成し、要約する

:しかし興味深い概要を注意してください。多くの場合、 の代わりにオブジェクト をストリームする参照またはポインタを使用するか、2つのストリーム間でストリームバッファを共有する方が適切です。

4

ストリームをコピーできない理由は、it doesn't make sense to copy a streamです。あなたがしようとしていることを説明すれば、確かにそれを行う方法があります。コピーできるデータの塊が必要な場合は、文字列を使用します。しかし、ストリームは文字列よりも接続に似ています。

+0

接続をコピーしたい場合はどうすればいいですか?つまり、私はファイルを読んでいて、後で読まなければならないことが分かっている行(または、行の集合を大量に格納する)に達します。コピーがストリーム内のその場所にあるようにストリームをコピーし、後でそれに戻ることができるようにすると便利です。 – VF1

+0

@ VF1それは一般に意味をなさない。それはいくつかの種類のストリームには意味をなさいかもしれませんが、ストリームの一般的な特徴として、それは賢明ではありません。 –

+0

私は必要なものを見つけたと思う(はい、それはistreamsのみ) - 'tellg'で現在のストリーム位置を保存し、' seekg'を後で使用します。 – VF1

1

もちろん、コピーコンストラクタとコピー代入演算子を自分で記述する必要があります。

次に、コピーに含めるセマンティクスを決定する必要があります。だから、:

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

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

あなたは浅いコピーをしたい場合は、("foobar"は)あなたはおそらく最高のは、そのためのshared_ptrを使用するように、TestStreamの複数のインスタンス間にstringstreamオブジェクトを共有する必要があります。

あなたは深いコピー("foo"を)したい場合は、次のようにコピーすることができます:

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

それともにリンク問題の変種のいずれかを使用します。

これは、コピーを取ったときにと書かれている文字列をカバーします。もしあなたがの中にいるのなら、それからを読むか、あなたが書いているがseekpの使用のために最後に書いていないかもしれないなら、現在の読み書き位置とあなたは​​で行うストリングストリームのデータです。

あなたは、ストリームのフォーマット状態間でコピーする、というように、copyfmtが何をするかである、とさえエラーフラグかもしれません(rdstateからcopyfmt単独でそれらを残します)。 Cで様々な書き込み操作のパフォーマンスをテストする++ここ

0

はあなたのマシン上でコンパイルとテストはいくつかの方法でバッファリングとすることなく、書き込み操作のコードです:

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(); 
} 
関連する問題