RapidXML чтение из файла - что здесь не так? - PullRequest
0 голосов
/ 16 июня 2011

В чем разница между этими двумя методами чтения входного файла?

1) Использование 'ifstream.get()'

и

2) Использование vector<char> с ifstreambuf_iterator<char> (менее понятным для меня!)

(кроме очевидного ответа о наличии изящных векторных методов для работы)

Входной файл - XML, и, как вы видите ниже, сразу же анализируетсяв документ rapidxml.(инициализирован в другом месте, см. пример основной функции.)

Сначала позвольте мне показать вам два способа написания функции load_config, один из которых использует ifstream.get(), а другой - vector<char>

Метод1 ifstream.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 приводит к закрытому документу rapidXML другой библиотекой, в частности, к вызову curl_global_init (CURL_GLOBAL_SSL) [см. Основной код ниже] - но я пока не виню его за 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.Этого не было в исходном коде, и это артефакт отладочных изменений.Исходный (ошибочный) код объявил его и не выделил его динамически, но возникли идентичные проблемы.

Еще один совет для полного раскрытия (хотя я не понимаю, почему это важно) - есть еще один экземпляр векторав этом беспорядке кода, который заполняется данными в объекте rapidxml :: xml_document.

1 Ответ

5 голосов
/ 16 июня 2011

Единственное различие между ними состоит в том, что версия vector работает правильно, а версия массива char вызывает неопределенное поведение, когда файл длиннее 65535 символов (он записывает \0 в 65535-ю или 65536-ю позицию,которые выходят за границы).

Другая проблема, которая характерна для обеих версий, заключается в том, что вы считываете файл в память с более коротким временем жизни, чем xml_document, Чтение документации:

Строка должна сохраняться в течение всего срока действия документа.

Когда load_config выходит из vector уничтожаетсяи память освобождается.Попытка доступа к документу вызывает чтение недопустимой памяти (неопределенное поведение).

В версии массива char память выделяется в стеке.Он все еще «освобожден», когда существует load_config (доступ к нему вызывает неопределенное поведение).Но вы не видите сбой, потому что он еще не был перезаписан.

...