Чтение и запись вектора C++ в файл

Поскольку некоторая графика работает, я должен читать в большом объеме данных как можно быстрее и идеально хотел бы непосредственно читать и записал бы структуры данных в диск. В основном у меня есть загрузка 3-х моделей в различных форматах файлов, которые занимают слишком много времени загружаться так, я хочу выписать им в их "подготовленном" формате как кэш, который загрузится намного быстрее на последующих выполнениях программы.

Действительно ли безопасно сделать это как это? Мои заботы вокруг прямого чтения в данные вектора? Я удалил проверку ошибок, трудно кодировали 4 как размер интервала и так далее так, чтобы я мог дать короткий рабочий пример, я знаю, что это - плохой код, мой вопрос действительно состоит в том, если безопасно в C++ считать целый массив структур непосредственно в вектор как это? Я полагаю, что это так, но C++ имеет столько прерываний и неопределенного behavour, когда Вы начинаете идти низкий уровень и иметь дело непосредственно с необработанной памятью как это.

Я понимаю, что числовые форматы и размеры могут измениться через платформы и компиляторы, но это будет только даже считано и записано той же программой компилятора в данные кэша, которые могут быть необходимы на более позднем выполнении той же программы.

#include <fstream>
#include <vector>

using namespace std;

struct Vertex
{
    float x, y, z;
};

typedef vector<Vertex> VertexList;

int main()
{
    // Create a list for testing
    VertexList list;
    Vertex v1 = {1.0f, 2.0f,   3.0f}; list.push_back(v1);
    Vertex v2 = {2.0f, 100.0f, 3.0f}; list.push_back(v2);
    Vertex v3 = {3.0f, 200.0f, 3.0f}; list.push_back(v3);
    Vertex v4 = {4.0f, 300.0f, 3.0f}; list.push_back(v4);

    // Write out a list to a disk file
    ofstream os ("data.dat", ios::binary);

    int size1 = list.size();
    os.write((const char*)&size1, 4);
    os.write((const char*)&list[0], size1 * sizeof(Vertex));
    os.close();


    // Read it back in
    VertexList list2;

    ifstream is("data.dat", ios::binary);
    int size2;
    is.read((char*)&size2, 4);
    list2.resize(size2);

     // Is it safe to read a whole array of structures directly into the vector?
    is.read((char*)&list2[0], size2 * sizeof(Vertex));

}
17
задан Peter Alexander 18 March 2010 в 12:17
поделиться

5 ответов

Как говорит Лауринас, std :: vector гарантированно будет смежным, так что это должно работать, но потенциально не переносимо.

В большинстве систем sizeof (Vertex) будет 12, но нередко структура дополняется, так что sizeof (Vertex) == 16 . Если вы должны были записать данные в одной системе, а затем прочитать этот файл в другой, нет гарантии, что он будет работать правильно.

20
ответ дан 30 November 2019 в 11:04
поделиться

Другой альтернативой явному чтению и записи вашего vector <> из и в файл является замена основного распределителя на тот, который выделяет память из файла с отображением памяти. Это позволит вам избежать промежуточного копирования, связанного с чтением / записью. Однако у этого подхода есть некоторые накладные расходы. Если ваш файл не очень большой, это может не иметь смысла в вашем конкретном случае. Профилируйте как обычно, чтобы определить, подходит ли этот подход.

К этому подходу также есть некоторые предостережения, которые очень хорошо обрабатываются библиотекой Boost.Interprocess . Особый интерес для вас могут быть его распределители и контейнеры .

2
ответ дан 30 November 2019 в 11:04
поделиться

std :: vector гарантированно будет непрерывным в памяти, так что да.

8
ответ дан 30 November 2019 в 11:04
поделиться

Если это используется для кэширования тем же кодом, я не вижу в этом никаких проблем. Я без проблем использовал эту технику на нескольких системах (все на базе Unix). В качестве дополнительной меры предосторожности вы можете захотеть написать структуру с известными значениями в начале файла и проверить, правильно ли она читается. Вы также можете записать размер структуры в файл. Это сэкономит много времени на отладку в будущем, если заполнение когда-либо изменится.

1
ответ дан 30 November 2019 в 11:04
поделиться

Возможно, вас заинтересует библиотека Boost.Serialization . Помимо прочего, он знает, как сохранять / загружать контейнеры STL на / с диска. Это может быть излишним для вашего простого примера, но может стать более полезным, если вы выполните другие типы сериализации в своей программе.

Вот пример кода, который делает то, что вы ищете:

#include <algorithm>
#include <fstream>
#include <vector>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/vector.hpp>

using namespace std;

struct Vertex
{
    float x, y, z;
};

bool operator==(const Vertex& lhs, const Vertex& rhs)
{
    return lhs.x==rhs.x && lhs.y==rhs.y && lhs.z==rhs.z;
}

namespace boost { namespace serialization {
    template<class Archive>
    void serialize(Archive & ar, Vertex& v, const unsigned int version)
    {
        ar & v.x; ar & v.y; ar & v.z;
    }
} }

typedef vector<Vertex> VertexList;

int main()
{
    // Create a list for testing
    const Vertex v[] = {
        {1.0f, 2.0f,   3.0f},
        {2.0f, 100.0f, 3.0f},
        {3.0f, 200.0f, 3.0f},
        {4.0f, 300.0f, 3.0f}
    };
    VertexList list(v, v + (sizeof(v) / sizeof(v[0])));

    // Write out a list to a disk file
    {
        ofstream os("data.dat", ios::binary);
        boost::archive::binary_oarchive oar(os);
        oar << list;
    }

    // Read it back in
    VertexList list2;

    {
        ifstream is("data.dat", ios::binary);
        boost::archive::binary_iarchive iar(is);
        iar >> list2;
    }

    // Check if vertex lists are equal
    assert(list == list2);

    return 0;
}

Обратите внимание, что мне пришлось реализовать функцию сериализации для вашей Vertex в повышении : : пространство имен serialization . Это позволяет библиотеке сериализации знать, как сериализовать элементы Vertex .

Я просмотрел исходный код boost :: binary_oarchive , и мне показалось, что он считывает / записывает необработанные данные векторного массива непосредственно из / в буфер потока. Так что это должно быть довольно быстро.

10
ответ дан 30 November 2019 в 11:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: