如何有效地管理数组中的堆对象(C++)

How to efficiently manage heap objects in array (C++)?

本文关键字:对象 C++ 有效地 管理 数组      更新时间:2023-10-16

我在实现一个解决方案时遇到了一些问题,该解决方案在循环中处理堆上的对象创建并将其存储在数组中。

我有一个代表股票交易的交易类。它包括自定义的日期和时间类,以及一些用于存储数值的双值。

我使用TransactionIO类从一个包含大约100条事务记录的CSV文件中读取这些。

我的算法如下:

While EOF not reached
  Read Transaction data
  Create Transaction object on heap
  Return pointer to newly created Transaction object
  Store 'Pointed-to-Transaction' in custom Vector
EndWhile

以下是TransactionIO函数ReadTransaction:的代码

// Reads in a transaction and returns it
Transaction* TransactionIO::ReadTransaction(ifstream& is)
{
    // Assuming file structure is a CSV file
    // With structure given as:
    // Date/Time, Price, Volume, Value, Condition
    Date date;
    Time time;
    double price, volume, value;
    string condition;
    string dateString, timeString;
    //cout << "nBegin Read..." << endl;
    getline(is, dateString, ',');       // read date/time string and then parse
    ReadNextDoubleField(price, is);
    ReadNextDoubleField(volume, is);
    ReadNextDoubleField(value, is);
    getline(is, condition);
    // split the date and time fields and parse them
    timeString = dateString.substr(dateString.find_first_of(" ") + 1);
    dateString.erase(dateString.find_first_of(" "));    // remove the time string - only need date string here
    date = ParseDate(dateString);    // Will change later to use pass by reference
    time = ParseTime(timeString);    // Will change later to use pass by reference
    // construct and return transaction that was read
    Transaction* transaction = new Transaction(date, time, price, volume, value, condition);
    return transaction
}

我还没有创建我的主类,因为我正在处理我的数据类。那么,使用这个函数的正确方法是什么呢?

我正计划这样做:

主回路中:

While(//file IO condition here...)
{
   p_transaction = TransactionIO::ReadTransaction(is);
   myCustomVector.Add(*transaction);
}

这样做对吗?我的自定义向量的Add方法需要一个常量T&引用以添加给定对象。

此外,对自定义向量的内部数组调用delete[]会删除存储在其中的对象吗?

我觉得我的代码效率很低,我的讲师警告我不要在循环中构造对象。我应该通过引用返回对象。

但在这种情况下,如果我尝试了,这不是无效的吗?

void TransactionIO::ReadTransaction(Transaction& transaction, ifstream& is)
{
   // Do all the reading and processing as given above....
   Transaction t1(date, time, price, volume, value, condition);
   transaction = t1;    // creating object AND call assignment op - not efficient?
}

在上面的行中,一旦该函数完成,t1将超出范围,对象将被销毁。那么,我的参考将指向什么呢?

这就是为什么我决定使用指针解决方案,但我觉得我的程序会有巨大的内存泄漏。。。

如有任何帮助和解释,我们将不胜感激。。。如果可能的话,我不仅想知道你答案的"如何",还想知道你的"为什么"。

最后,不。我不能使用STL容器。我必须使用我自己的向量类(我已经测试过了,效果很好。)

我同意您最好通过堆栈分配对象。

堆分配相对昂贵,在您的情况下是不必要的,因为在将对象复制到向量中之前,您只将指针用作临时存储。然后你需要删除那些指针,我看你不会这么做。

在这种情况下:

void TransactionIO::ReadTransaction(Transaction& transaction, ifstream& is)
{
   // Do all the reading and processing as given above....
   Transaction t1(date, time, price, volume, value, condition);
   transaction = t1;    // creating object AND call assignment op - not efficient?
}

您并没有将transaction设置为对t1的引用,而是将t1的内容分配给transaction所引用的对象。您甚至可以使用transaction = std::move(t1);显式地使用移动赋值运算符(只要您定义了一个或您的类符合隐式定义的规则),并消除对副本的需要。

然而,您甚至不需要传入引用,如果您只是按值返回,编译器将删除副本,而不是直接分配到调用站点。这就是所谓的回报价值优化。因此,您可以执行以下操作:

Transaction TransactionIO::ReadTransaction(ifstream& is)
{
   // Do all the reading and processing as given above....
   return Transaction(date, time, price, volume, value, condition);
}

或者在C++11:中

Transaction TransactionIO::ReadTransaction(ifstream& is)
{
   // Do all the reading and processing as given above....
   return {date, time, price, volume, value, condition};
}

如果循环运行时间很长,那么在循环中分配对象的效率很低。

你可以做的一件事是预先分配你的向量,但如果你不知道你需要什么大小,这也可能是低效的。在STL中,您可以使用保留:http://www.cplusplus.com/reference/vector/vector/reserve/但在您的情况下,您需要在向量类中实现类似的东西。

在上面的行中,一旦该函数完成,t1将退出范围和对象将被销毁。那么我的参考资料是什么指向?未定义的行为,除非Transaction是某种智能指针。

此外,将对自定义向量的内部数组调用delete[]删除存储在其中的对象?

如果我理解得很好,是的。

因此,您可以保留向量的大小(如果您有一个很好的估计大小),然后填充已经创建的槽。这样,矢量就不需要如此频繁地扩展大小。