Позволяя `std :: vector`украсть память из` std :: string` - PullRequest
0 голосов
/ 23 июня 2018

Предположим, у нас есть std::string s, содержащий буфер необработанных данных, но вместо этого мы хотим std::vector<uint8_t> v. Длина буфера в миллионах. Есть ли простой способ позволить v украсть память s и таким образом избежать копирования буфера?

Как то, что std::vector<uint8_t>::vector(std::string&&) сделал бы, но делал это как-то снаружи STL.

Или же можно получить v из std::stringstream ss с помощью операции, столь же эффективной, как ss.str()?

1 Ответ

0 голосов
/ 24 июня 2018

ОК, там много комментариев, давайте попробуем собрать что-то вместе, потому что мне нужна практика и, возможно, я смогу заработать несколько очков [обновление: не: (].

Я довольно новичок в "современном C ++", поэтому, пожалуйста, примите его, как только найдете. Может потребоваться уже в C ++ 17, я не проверил это слишком тщательно. Любая критика более чем приветствуется, но я бы предпочел редактировать свой собственный пост. И, пожалуйста, помните, читая это, что OP на самом деле хочет сделать, это прочитать его байты из файла. Thx.

Обновление: Настроен для обработки случая, когда размер файла изменяется между вызовом stat() и вызовом fread() согласно комментарию @ Deduplicator ниже ... и впоследствии заменен fread с std::ifstream, я думаю, мы сейчас там.

#include <string>
#include <vector>
#include <optional>
#include <iostream>
#include <fstream>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

using optional_vector_of_char = std::optional <std::vector <char>>;

// Read file into a std::optional <std::vector <char>>.
// Now handles the file size changing when we're not looking.
optional_vector_of_char SmarterReadFileIntoVector (std::string filename)
{
    for ( ; ; )
    {
        struct stat stat_buf;
        int err = stat (filename.c_str (), &stat_buf);
        if (err)
        {
            // handle the error
            return optional_vector_of_char ();   // or maybe throw an exception
        }

        size_t filesize = stat_buf.st_size;

        std::ifstream fs;
        fs.open (filename, std::ios_base::in | std::ios_base::binary);
        if (!fs.is_open ())
        {
            // handle the error
            return optional_vector_of_char ();
        }

        optional_vector_of_char v (filesize + 1);
        std::vector <char>& vecref = v.value ();
        fs.read (vecref.data (), filesize + 1);

        if (fs.rdstate () & std::ifstream::failbit)
        {
            // handle the error
            return optional_vector_of_char ();
        }

        size_t bytes_read = fs.gcount ();
        if (bytes_read <= filesize)              // file same size or shrunk, this code handles both
        {
            vecref.resize (bytes_read);
            vecref.shrink_to_fit ();
            return v;                            // RVO
        }

        // File has grown, go round again
    }
}    

int main ()
{
    optional_vector_of_char v = SmarterReadFileIntoVector ("abcde");
    std::cout << std::boolalpha << v.has_value () << std::endl;
}

Живая демоверсия . Конечно, нет доступных файлов для чтения, так что ...


Также : Рассматривали ли вы написание собственного простого контейнера, отображающего вид файла? Просто мысль.

...