如何有效地管理数组中的堆对象(C++)?
How to efficiently manage heap objects in array (C++)?
我在实施解决方案时遇到了一些问题,该解决方案在循环中处理堆上的对象创建并将其存储在数组中。
我有一个代表股票交易的交易 class。它包括自定义日期和时间 classes 以及一些用于存储数值的双精度值。
我使用我的 TransactionIO class 从包含大约 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
}
我还没有创建我的主要 class,因为我正在处理我的数据 classes。那么这个函数的正确使用方法是什么?
我打算这样做:
在主循环中:
While(//file IO condition here...)
{
p_transaction = TransactionIO::ReadTransaction(is);
myCustomVector.Add(*transaction);
}
这样做正确吗?我的自定义向量的 Add 方法需要一个 const T& 引用来添加给定的对象。
此外,对自定义向量的内部数组调用 delete[] 是否会删除存储在其中的对象?
我觉得我的代码效率很低,我的讲师警告我不要在循环中构造对象。我应该 return 引用对象。
但在这种情况下,如果我尝试了,这不是无效的吗?
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 将超出范围并且对象将被销毁。那么我的引用将指向什么?
这就是我决定采用指针解决方案的原因,但我觉得我的程序会有很大的内存泄漏...
如有任何帮助和解释,我们将不胜感激...如果可能的话,我不仅想知道 'how',而且还想知道 'why'。
最后,没有。我不能使用 STL 容器。我必须使用我自己的矢量 class(我已经测试过了,效果很好。)
如果对象的长度很长 运行,则在循环中分配对象效率低下。
您可以做的一件事是预先分配向量,但如果您不知道需要的大小,它也可能效率低下。
在 STL 中你可以使用 reserve: http://www.cplusplus.com/reference/vector/vector/reserve/
但在你的情况下,你需要在你的向量中实现类似的东西 class.
In the above line, once this function completes, t1 will go out of
scope and the object will destroyed. So what will my reference be
pointing to?
Undefined behavior, except if Transaction is some kind of smart pointer.
Also, will calling delete[] on my custom vector's internal array
delete the objects being stored in it?
如果我理解的不错,是的。
所以您可以保留向量的大小(如果您有一个很好的估计大小),然后填充已经创建的槽。
这样你的向量就不需要如此频繁地扩展大小。
我同意您最好对对象进行堆栈分配。
堆分配相对昂贵,在您的情况下是不必要的,因为在将对象复制到向量中之前,您仅将指针用作临时存储。然后你需要删除那些指针,我没有看到你这样做。
在这种情况下:
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);
显式使用移动赋值运算符(只要您定义了一个或您的 class 满足隐式定义的规则)并消除对副本的需要。
但是,您甚至不需要传入引用,如果您只是按值 return 编译器将省略副本,而是直接分配到调用站点。这被称为 Return Value Optimisation。因此,您只需执行以下操作:
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};
}
我在实施解决方案时遇到了一些问题,该解决方案在循环中处理堆上的对象创建并将其存储在数组中。
我有一个代表股票交易的交易 class。它包括自定义日期和时间 classes 以及一些用于存储数值的双精度值。
我使用我的 TransactionIO class 从包含大约 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
}
我还没有创建我的主要 class,因为我正在处理我的数据 classes。那么这个函数的正确使用方法是什么?
我打算这样做:
在主循环中:
While(//file IO condition here...)
{
p_transaction = TransactionIO::ReadTransaction(is);
myCustomVector.Add(*transaction);
}
这样做正确吗?我的自定义向量的 Add 方法需要一个 const T& 引用来添加给定的对象。
此外,对自定义向量的内部数组调用 delete[] 是否会删除存储在其中的对象?
我觉得我的代码效率很低,我的讲师警告我不要在循环中构造对象。我应该 return 引用对象。
但在这种情况下,如果我尝试了,这不是无效的吗?
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 将超出范围并且对象将被销毁。那么我的引用将指向什么?
这就是我决定采用指针解决方案的原因,但我觉得我的程序会有很大的内存泄漏...
如有任何帮助和解释,我们将不胜感激...如果可能的话,我不仅想知道 'how',而且还想知道 'why'。
最后,没有。我不能使用 STL 容器。我必须使用我自己的矢量 class(我已经测试过了,效果很好。)
如果对象的长度很长 运行,则在循环中分配对象效率低下。
您可以做的一件事是预先分配向量,但如果您不知道需要的大小,它也可能效率低下。 在 STL 中你可以使用 reserve: http://www.cplusplus.com/reference/vector/vector/reserve/ 但在你的情况下,你需要在你的向量中实现类似的东西 class.
In the above line, once this function completes, t1 will go out of scope and the object will destroyed. So what will my reference be pointing to? Undefined behavior, except if Transaction is some kind of smart pointer.
Also, will calling delete[] on my custom vector's internal array delete the objects being stored in it?
如果我理解的不错,是的。
所以您可以保留向量的大小(如果您有一个很好的估计大小),然后填充已经创建的槽。 这样你的向量就不需要如此频繁地扩展大小。
我同意您最好对对象进行堆栈分配。
堆分配相对昂贵,在您的情况下是不必要的,因为在将对象复制到向量中之前,您仅将指针用作临时存储。然后你需要删除那些指针,我没有看到你这样做。
在这种情况下:
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);
显式使用移动赋值运算符(只要您定义了一个或您的 class 满足隐式定义的规则)并消除对副本的需要。
但是,您甚至不需要传入引用,如果您只是按值 return 编译器将省略副本,而是直接分配到调用站点。这被称为 Return Value Optimisation。因此,您只需执行以下操作:
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};
}