0

入力ファイルを読み取るこれら 2 つの方法の違いは何ですか?

1) 使用'ifstream.get()'

2) vector<char>withの使用ifstreambuf_iterator<char> (私にはあまり理解されていません!)

(気の利いたベクトルメソッドを使用するという明白な答えを除いて)

入力ファイルは XML であり、以下に示すように、すぐに rapidxml ドキュメントに解析されます。(他の場所で初期化されます。メイン関数の例を参照してください。)

最初に、'load_config' 関数を記述する 2 つの方法を紹介しますifstream.get()vector<char>

方法 1ifstream.get()は、動作するコードと安全な RapidXML ドキュメント オブジェクトを提供します。

rapidxml::xml_document<> *load_config(rapidxml::xml_document<> *doc){
   ifstream myfile("inputfile");

   //read in config file
   char ch;
   char buffer[65536];
   size_t chars_read = 0;

   while(myfile.get(ch) && (chars_read < 65535)){
      buffer[chars_read++] = ch;
   }
   buffer[chars_read++] = '\0';

   cout<<"clearing old doc"<<endl;
   doc->clear();

   doc->parse<0>(buffer);

   //debug returns as expected here
   cout << "load_config: Name of my first node is: " << doc->first_node()->name() << "\n";

   return doc;
}

方法 2 では、別のライブラリ (具体的には curl_global_init(CURL_GLOBAL_SSL) の呼び出し [以下のメイン コードを参照]) によってクローバー化された rapidXML ドキュメントが生成されますが、まだ curl_global_init のせいではありません。

rapidxml::xml_document<> *load_config(rapidxml::xml_document<> *doc){
   ifstream myfile("inputfile");

   vector<char> buffer((istreambuf_iterator<char>(inputfile)), 
                istreambuf_iterator<char>( ));
   buffer.push_back('\0');

   cout<<"file looks like:"<<endl;  //looks fine
   cout<<&buffer[0]<<endl;

   cout<<"clearing old doc"<<endl;
   doc->clear();

   doc->parse<0>(&buffer[0]);

   //debug prints as expected
   cout << "load_config: Name of my first node is: " << doc->first_node()->name() << "\n";

   return doc;
}

メインコード:

int main(void){
   rapidxml::xml_document *doc;
   doc = new rapidxml::xml_document;

   load_config(doc);

   // this works fine:
   cout << "Name of my first node is: " << doc->first_node()->name() << "\n"; 

   curl_global_init(CURL_GLOBAL_SSL);  //Docs say do this first.

   // debug broken object instance:
   // note a trashed 'doc' here if using vector<char> method 
   //  - seems to be because of above line... name is NULL 
   //    and other nodes are now NULL
   //    causing segfaults down stream.
   cout << "Name of my first node is: " << doc->first_node()->name() << "\n"; 

これはすべて単一のスレッドで実行されると確信していますが、私の理解を超えた何かが起こっている可能性があります。

ファイルロード機能を変更するだけで、原因ではなく症状だけを修正したことも心配です。ここでコミュニティに助けを求めてください!

質問: ベクトルから文字配列に移動すると、これが修正されるのはなぜですか?

ヒント: RapidXML は、実際に入力文字列に直接アクセスする巧妙なメモリ管理を使用していることを認識しています。

ヒント: 上記のメイン関数は、動的な (新しい) xml_document を作成します。これは元のコードにはなく、変更をデバッグした結果です。元の (失敗した) コードはそれを宣言し、動的に割り当てませんでしたが、同じ問題が発生しました。

完全な開示のためのもう 1 つのヒント (なぜそれが重要なのかはわかりませんが) - このコードの混乱には、rapidxml::xml_document オブジェクトのデータによって取り込まれたベクトルの別のインスタンスがあります。

4

1 に答える 1

5

この 2 つの唯一の違いは、ファイルが 65535 文字を超えるとバージョンがvector正しく機能し、配列バージョンが未定義の動作を引き起こすことです (境界外である 65535 番目または 65536 番目の位置に を書き込みます)。char\0

両方のバージョンに共通するもう 1 つの問題は、 xml_document. ドキュメントを読む:

文字列は、ドキュメントの存続期間中存続する必要があります。

load_config終了すると、vectorが破棄され、メモリが解放されます。ドキュメントにアクセスしようとすると、無効なメモリが読み取られます (未定義の動作)。

配列バージョンではchar、メモリはスタックに割り当てられます。存在する場合でも「解放」されload_configます (アクセスすると未定義の動作が発生します)。ただし、まだ上書きされていないため、クラッシュは表示されません。

于 2011-06-15T20:30:10.413 に答える