Вопрос:

Запись содержимого вектора в файл в виде двоичных данных

c++ vector

604 просмотра

2 ответа

49 Репутация автора

У меня есть некоторый 15-летний код C ++, который я пытаюсь привести в более современное время. На этом этапе я пытаюсь получить код, скомпилированный с Visual C ++ 6.0, который теперь компилируется с VS 2003 (Microsoft Visual C ++ .NET 69462-335-0000007-18915).

std::vector<myClassType> myVect;
...

// Assuming vector.begin() simply points to start of a contiguous array
bool OK = File.write((char*) myVect.begin(),
                     myVect.size() * sizeof(myClassType));

Когда я читаю комментарий, я волнуюсь ... Можем ли мы предположить, что вектор находится в смежной памяти? Если нет, как лучше это сделать? Нужно ли циклически просматривать содержимое вектора и записывать каждый набор данных из myClassType?

Как таковой, компилятор жалуется на приведение результата begin () к char * в любом случае.

Автор: Todd Hoatson Источник Размещён: 08.11.2017 10:53

Ответы (2)


4 плюса

365692 Репутация автора

Решение

std::vectorгарантированно хранит его элементы в смежной памяти, поэтому все, что вы пытаетесь сделать, это нормально, при условии, что myClassTypeэто тип POD . В противном случае вам нужно будет по очереди выполнить std::vectorсериализацию каждого элемента по одному в плоский формат по мере необходимости.

Однако std::vector::begin()метод возвращает итератор для первого элемента, а не указатель на данные элемента. Итератор похож на указатель, но не указатель. Реализации контейнеров могут использовать фактические указатели в качестве итераторов, но чаще они используют классы-обертки. Не полагайтесь на это поведение! Используйте API итератора так, как он предназначен для использования, и не предполагайте, что итератор является фактическим указателем.

Чтобы получить действительный указатель на данные первого элемента вашего вектора, вам необходимо:

  1. используйте std::vector::data()(только C ++ 11 и более поздние версии):

    myVect.data()
    

    Это безопасно использовать, даже если вектор пуст. data()может возвращаться или не возвращаться, nullptrкогда size()0, но это нормально, так write()как не будет пытаться получить доступ к какой-либо памяти, когда size()0.

    bool OK = File.write((char*) myVect.data(), myVect.size() * sizeof(myClassType));
    
  2. используйте, std::vector::operator[]чтобы получить ссылку на первый элемент, затем используйте, operator&чтобы получить адрес элемента:

    &myVect[0]
    

    Обратите внимание, что operator[]проверка границ не выполняется, и, следовательно, вернет неопределенный указатель, если указанный индекс>> size(), поэтому убедитесь, что вектор пустой перед записью:

    bool OK = myVect.empty() || File.write((char*) &myVect[0], myVect.size() * sizeof(myClassType));
    
  3. такой же как # 2, но std::vector::front()вместо этого используется :

    &myVect.front()
    

    Обратите внимание, что вызов front()пустого вектора является неопределенным поведением, поэтому убедитесь, что вектор пустой:

    bool OK = myVect.empty() || File.write((char*) &myVect.front(), myVect.size() * sizeof(myClassType));
    
  4. используйте, begin()чтобы получить итератор для первого элемента, затем используйте operator*для разыменования итератор, чтобы получить ссылку на элемент, на который он указывает, затем вы можете получить адрес элемента:

    &(*(myVect.begin()))
    

    Обратите внимание, что begin()возвращает end()итератор, когда вектор пуст, и разыменование end()итератора является неопределенным поведением, поэтому убедитесь, что вектор пустой:

    bool OK = myVect.empty() || File.write((char*) &(*(myVect.begin())), myVect.size() * sizeof(myClassType));
    
Автор: Remy Lebeau Размещён: 08.11.2017 11:04

4 плюса

8453 Репутация автора

Ответ Реми Лебо правильный. Чтобы добавить к этому, если вы хотите повысить безопасность своего кода, вы должны также использовать его, static_assertчтобы убедиться, что myClassTypeписать безопасно так, как вы хотите:

#include <type_traits>
static_assert(std::is_pod_v<myClassType>, "myClassType is potentialy unsafe to write as-is");

Если myClassTypeв будущем кто-то изменится таким образом, что это File.write()станет небезопасным для использования в вашем коде, эта проверка во время компиляции поймает его.

Автор: NoSenseEtAl Размещён: 08.11.2017 11:30
Вопросы из категории :
32x32