【问题标题】:Dynamic allocation of a vector inside a struct while reading a large txt file读取大型 txt 文件时在结构内动态分配向量
【发布时间】:2019-12-17 04:46:04
【问题描述】:

我目前正在学习 C++ 语言,需要读取一个包含 5000 多个双精度型数字的文件。由于push_back 会在分配新数据时进行复制,因此我试图找出一种减少计算工作的方法。请注意,该文件可能包含随机数量的双精度类型,因此通过指定足够大的向量来分配内存并不是要寻找的解决方案。

我的想法是快速读取整个文件并获取数组的近似大小。在Save & read double vector from file C++?发现了一个有趣的想法,可以在下面的代码中找到。

基本上,包含文件数据的向量被插入到名为PathStruct 的结构类型中。请记住,PathStruct 包含比这个向量更多的内容,但为了简单起见,我删除了所有其余部分。该函数接收PathStruct指针的引用并读取文件。

struct PathStruct
{
    std::vector<double> trivial_vector;
};

bool getFileContent(PathStruct *&path)
{
    std::ifstream filename("simplePath.txt", std::ios::in | std::ifstream::binary);
    if (!filename.good())
        return false;
    std::vector<char> buffer{};
    std::istreambuf_iterator<char> iter(filename);
    std::istreambuf_iterator<char> end{};
    std::copy(iter, end, std::back_inserter(buffer));
    path->trivial_vector.reserve(buffer.size() / sizeof(double));
    memcpy(&path->trivial_vector[0], &buffer[0], buffer.size());
    return true;
};

int main(int argc, char **argv)
{

    PathStruct *path = new PathStruct;

    const int result = getFileContent(path);

    return 0;
}

当我运行代码时,编译器给出以下错误:

损坏的大小与 prev_size,中止(核心转储)。

我认为我的问题在于不正确使用指针。绝对不是我的强项,但我找不到问题。我希望有人能帮助这个可怜的灵魂。

【问题讨论】:

  • 您知道文件将包含的最低数据量吗?
  • 分配两个向量没有意义(只是看你的代码),这似乎只是浪费资源。此外,我认为一个关键点是你的双打是如何在文件中编码的。二进制形式? ASCII/文本表示(具有固定长度?)等
  • 5000 double 占用高达 40kB 的内存,我只保留一个合理的最大大小并使用 push_back,保持简单。如果你发现速度很慢,那就是开始优化的时候了。
  • 你的代码的问题是调用reserve而不是resize,这意味着向量仍然是空的,所以你不能写入它
  • “.txt”后缀通常与文本一起使用。

标签: c++ memory vector dynamic memcpy


【解决方案1】:

如果您的文件只包含连续的 double 值,您可以检查文件大小并将其除以 double 大小。要确定文件大小,您可以使用std::filesystem::file_size,但此功能在 C++ 17 中可用。如果您不能使用 C++ 17,您可以找到其他确定文件大小的方法here

auto fileName = "file.bin";
auto fileSize = std::filesystem::file_size(fileName);
std::ifstream inputFile("file.bin", std::ios::binary);
std::vector<double> values;
values.reserve(fileSize / sizeof(double));
double val;
while(inputFile.read(reinterpret_cast<char*>(&val), sizeof(double)))
{
    values.push_back(val);
}

或使用指针:

auto numberOfValues = fileSize / sizeof(double);
std::vector<double> values(numberOfValues);
// Notice that I pass numberOfValues * sizeof(double) as a number of bytes to read instead of fileSize
// because the fileSize may be not divisable by sizeof(double)
inputFile.read(reinterpret_cast<char*>(values.data()), numberOfValues * sizeof(double));

另类

如果可以修改文件结构,可以在文件开头添加多个double值,在读取double值之前读取这个数字。这样,您将始终知道要读取的值的数量,而无需检查文件大小。

备选方案 2

您还可以将容器从 std::vector 更改为 std::deque。这个容器类似于 std::vector,但它没有为数据保留单个缓冲区,它有可能更小的数组。如果您正在插入数据并且数组已满,则将分配和链接额外的数组而不复制以前的数据。 然而,这有一个很小的代价,数据访问需要两个指针取消引用而不是一个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-17
    • 2020-06-20
    • 1970-01-01
    • 2018-11-13
    • 2015-08-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多