Создание вектора C ++, который указывает на уже выделенную память - PullRequest
2 голосов
/ 17 марта 2020

Я работаю с более старым кодом, который размещает часть оперативной памяти и загружает в нее двоичный файл. Двоичный файл представляет собой серию 8-битных плоскостей серого изображения размером X по Y, глубиной по Z. Размер файлов обычно составляет от 500 мегабайт до 10 гигабайт.

Существующий код использует сложное расположение указателей для доступа к отдельным плоскостям в плоскостях XY, XZ или YZ.

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

На основании этого предыдущего вопроса ( Можно ли инициализировать std :: вектор над уже выделенной памятью? ) У меня есть следующий код

//preallocate.h
template <typename T>
class PreAllocator
{
private:
T* memory_ptr;
std::size_t memory_size;

public:
typedef std::size_t     size_type;
typedef T*              pointer;
typedef T               value_type;

PreAllocator(T* memory_ptr, std::size_t memory_size) : memory_ptr(memory_ptr), memory_size(memory_size) {}

PreAllocator(const PreAllocator& other) throw() : memory_ptr(other.memory_ptr), memory_size(other.memory_size) {};

template<typename U>
PreAllocator(const PreAllocator<U>& other) throw() : memory_ptr(other.memory_ptr), memory_size(other.memory_size) {};

template<typename U>
PreAllocator& operator = (const PreAllocator<U>& other) { return *this; }
PreAllocator<T>& operator = (const PreAllocator& other) { return *this; }
~PreAllocator() {}


pointer allocate(size_type n, const void* hint = 0) {return memory_ptr;}
void deallocate(T* ptr, size_type n) {}

size_type max_size() const {return memory_size;}
};

Упрощенная основная функция выглядит следующим образом:

TOMhead header;
uint8_t* TOMvolume;
size_t volumeBytes = 0;

int main(int argc, char *argv[])
{
    std::fstream TOMfile;
    std::ios_base::iostate exceptionMask = TOMfile.exceptions() | std::ios::failbit| std::ifstream::badbit;
    TOMfile.exceptions(exceptionMask);

    try {
        TOMfile.open(argv[1],std::ios::in|std::ios::binary);
    }
    catch (std::system_error& error) {
        std::cerr << error.code().message() << std::endl;
        return ERROR;
    }

    TOMfile.read((char*) &header, sizeof(header));
    if (!TOMfile)
    {
        std::cout<<"Error reading file into memory, expected to read " << sizeof(header) << " but only read " << TOMfile.gcount() << "bytes" <<std::endl;
        return ERROR;
    }


    TOMfile.seekg(std::ios_base::beg);      // rewind to begining of the file
    TOMfile.seekg(sizeof(header));          // seek to data beyond the header

    volumeBytes = (header.xsize * header.ysize * header.zsize);

    std::cout << "Trying to malloc " << volumeBytes << " bytes of RAM" << std::endl;

    TOMvolume = (uint8_t*) malloc(volumeBytes);
    if (TOMvolume == NULL)
    {
        std::cout << "Error allocating RAM for the data" << std::endl;
        return ERROR;
    }
TOMfile.read((char*) TOMvolume,volumeBytes);

Я пытался затем использовать предварительно распределитель, чтобы создать вектор, который содержит эти малые c 'ed данные

std::vector<uint8_t, PreAllocator<uint8_t>> v_TOMvolume(0, PreAllocator<uint8_t>(&TOMvolume[0], volumeBytes));
v_TOMvolume.push_back(volumeBytes);

, но любая попытка прочитать размер вектора или любые данные в векторе не удалась. Данные верны в памяти, когда я просто использую отладчик для их просмотра, они просто не связываются с вектором, как мне бы хотелось.

Есть мысли? Возможно ли то, что я пытаюсь сделать?

1 Ответ

2 голосов
/ 17 марта 2020

Невозможно выделить память для вектора при сохранении предыдущего содержимого памяти.

Рабочий подход:

  • Не использовать mallo c при all.
  • Создание вектора с распределителем по умолчанию с необходимым размером.
  • Загрузка двоичного файла непосредственно в вектор.

В гипотетическом случае где вы не можете коснуться части размещения, потому что она находится где-то глубоко в библиотеке: просто не используйте вектор. У вас уже есть массив Dynami c. Алгоритмы на основе итераторов прекрасно работают с указателями. Для алгоритмов, основанных на диапазоне, вам нужно что-то вроде std::span (C ++ 20) или аналогичное.

Но использование вектора для выделения будет более безопасным и, следовательно, лучше.

Если ваши файлы до 10 ГБ, тогда я бы предложил вместо этого попробовать сопоставление памяти с файлом. Отображенная память также не может использоваться в качестве хранилища вектора, поэтому следует использовать подход, не использующий вектор. К сожалению, стандартного способа хранения файлов карты памяти не существует.

...