Чтение RapidXML из файла - что здесь не так?

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

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.


person FlipMcF    schedule 15.06.2011    source источник
comment
Что в нем sexy? Это показ мод?   -  person Nawaz    schedule 16.06.2011
comment
Поскольку единственная разница заключается в том, как данные считываются из файла, эти вопросы кажутся связанными: a-file-into-a-stdstring-in-c" title="как лучше всего преобразовать файл в стандартную строку в c"> stackoverflow.com/questions/116038/ stackoverflow.com/questions/195323/   -  person Robᵩ    schedule 16.06.2011
comment
в качестве проверки работоспособности вы можете настроить отладчик для проверки памяти, начиная с &buffer[0] для обоих вызовов до и после parse(), и посмотреть, одинаковы ли они во всех случаях?   -  person ribram    schedule 16.06.2011
comment
у вас все еще есть ошибка. Когда вы выходите из цикла из-за того, что chars_read < 65535 является ложным, это означает, что chars_read == 65535, а затем вы получаете доступ к 65535-й позиции, которая находится после конца массива.   -  person Yakov Galka    schedule 16.06.2011
comment
спасибо ybungalobill. Не следует сбрасывать со счетов это вообще. Заметили, оценили и исправили.   -  person FlipMcF    schedule 16.06.2011


Ответы (1)


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

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

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

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

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

person Yakov Galka    schedule 15.06.2011
comment
это конечно ответ. В конце концов также возникли проблемы с версией массива символов. как ключевое слово «static» в функции, так и, в конечном итоге, перемещение области буфера в основную решенную проблему. Спасибо! - person FlipMcF; 16.06.2011