【问题标题】:creating large number of object pointers创建大量对象指针
【发布时间】:2018-01-08 10:36:39
【问题描述】:

我已经定义了一个这样的类:

  class myClass {
       private:
            int count;
            string name;
       public:
            myClass (int, string);
            ...
            ...
  };

  myClass::myClass(int c, string n)
  {
        count = c;
        name = n;
  }
  ...
  ...

我还有一个 *.txt 文件,每一行都有一个名称:

David
Jack
Peter
...
...

现在我逐行读取文件并为每一行创建一个新的对象指针并将所有对象存储在一个向量中。函数是这样的:

vector<myClass*> myFunction (string fileName)
{
     vector<myClass*> r;
     myClass* obj;
     ifstream infile(fileName);
     string line;
     int count = 0;
     while (getline(infile, line))
     {
          obj = new myClass (count, line);
          r.push_back(obj);
          count++;
     }
     return r;
}

对于小的 *.txt 文件我没有问题。但是,有时我的 *.txt 文件包含超过 100 万行。在这些情况下,程序非常缓慢。你有什么建议可以让它更快吗?

【问题讨论】:

  • 您阅读此文本文件的频率如何?启动时只有一次?该程序将运行多长时间?只是几秒钟或几分钟,或几小时甚至几天? “长时间”是相对的,取决于您执行“长时间”操作的次数,以及与运行时其余部分相比的时间。
  • 您可以将较少的文件加载到内存中,并且只加载您需要的文件部分
  • 另外,你用这些数据做什么?用例是什么?您需要一次阅读所有内容吗?您事先对文件中的条目数有任何想法吗?如果这样做,那么您可以为向量预分配内存吗?
  • 我在启动时读取了一次文件。对于 100 万行的 txt 文件,将对象存储在向量中需要 15 分钟。问题是这只是一个更大的项目的一部分,15 分钟对我来说太长了。
  • wc (Linux/UNIX) 这样对文件进行一些琐碎的操作需要多长时间?你的 C++ 程序不应该比这慢得多....

标签: c++ object vector ifstream


【解决方案1】:

首先,找到比标准流更快的 io。

第二,你能用字符串视图代替字符串吗?它们是 C++17,但到处都有 C++11 及更早的版本。

第三,

myClass::myClass(int c, string n) {
  count = c;
  name = n;
}

应该阅读

myClass::myClass(int c, std::string n):
  count(c),
  name(std::move(n))
{}

这会对长名称产生影响。由于“小字符串优化”,短的没有。

第四,停止制作指针向量。创建值向量。

第五,失败了,找到一种更有效的方法来分配/解除分配对象。

【讨论】:

    【解决方案2】:

    您可以做的一件事是直接将您从文件中读取的string 移动到您正在创建的对象中:

    myClass::myClass(int c, string n)
      : count{c}, name{std::move(n)}
    { }
    

    您还可以进行基准测试:

    myClass::myClass(int c, string&& n)
      : count{c}, name{std::move(n)}
    { }
    

    上面的第一个版本将在调用函数时复制line,然后让myClass 对象接管用于该副本的动态分配的缓冲区。第二个版本(带有string&amp;&amp; n 参数)将让myClass 对象直接撕掉line 的缓冲区:这意味着对文本数据的复制更少,而且行的每一行都可能被剥离任何缓冲区文件被读入。希望您的分配通常能够从输入缓冲区中看到line 需要在下一行读取多大容量,并避免任何额外的分配/复制。与往常一样,衡量您何时有理由关心。

    虽然您将指针存储在向量中而不是存储 myClass 对象 按值 使得任何向量都可以调整大小,但您可能会通过预先为向量保留空间来获得小胜利相对便宜。与此相反,存储指针确实意味着您正在进行额外的动态分配。

    您可以做的另一件事是增加流缓冲区大小:请参阅pubsetbuf 和其中的示例。

    如果速度非常重要,您应该对文件进行内存映射并将指针存储到内存映射区域,而不是从文件流缓冲区复制到不同字符串内的不同动态分配内存区域。这很容易产生巨大的差异 - 可能多达一个数量级 - 但很大程度上取决于您的磁盘速度等。因此,如果您有理由关心,请对两者进行基准测试。

    【讨论】:

    • 对于存储指针,那么新的 C++17 std::string_view 类会很有用。
    • @Someprogrammerdude: 是的,虽然他们也有义务跟踪长度,在某些情况下,只有一个指针(或者甚至是文件偏移量,如果它可以小于你的指针,那么它可能会更快)大小),并依靠内存映射图像中的换行符来分隔字符串。对于更长的字符串,string_view 越来越引人注目。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多