我正在阅读和做Stanley Lippman的C++初级读本Ed.5中的练习。
我的代码有以下问题:当我更新std::vector<Sales_data> vec;
中现有的Sales_data
对象时,程序崩溃。
为了克服这一点,我删除了现有的Sales_data
对象,并用新的更新对象替换它。
有没有一种更有效的方法可以在不擦除Sales_data
对象然后替换它的情况下做到这一点?
我的代码:
#include <iostream>
#include <vector>
struct Sales_data
{
std::string isbn() const{ return this->bookNo; }
Sales_data& combine(const Sales_data &rhs)
{
this->units_sold += rhs.units_sold;
this->revenue += rhs.revenue*rhs.units_sold;
return *this;
}
Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
Sales_data sum =lhs;
sum.combine(rhs);
return sum;
}
std::string bookNo;
unsigned units_sold =0;
double revenue =0.0;
};
int main()
{
Sales_data book;
std::vector<Sales_data> vec;
while(std::cin>>book.bookNo>>book.units_sold>>book.revenue)
{
for(auto it =vec.begin(); !vec.empty()&&it!=vec.end(); ++it)
{
if(book.bookNo == it->isbn()) //Check to see if book exists if vec
{
Sales_data add_book =it->add(*it, book);
vec.erase(it); //must erase to prevent a crash
vec.push_back(add_book);
}
}
//Some code for new Sales_data entry
}
return 0;
}
vec.erase(it);
会使it
无效,因此当循环继续时,您会有未定义的行为。
有没有一种更有效的方法可以做到这一点,而不必擦除Sales_data对象然后替换它?
是,请使用combine
而不是add
。
旁白:你能使用标准的算法吗,比如std::find_if
?
while(std::cin >> book.bookNo >> book.units_sold >> book.revenue) {
auto it = std::find_if(vec.begin(), vec.end(), [&](auto & other){ return book.isbn() == other.isbn(); });
if (it != vec.end()) {
it->combine(book);
} else {
vec.push_back(book);
}
}
我还建议将您的输入移动到std::istream& operator>>(std::istream & is, Sales_data & data)
中。
在迭代集合时,不允许修改集合。push_back
就是一个例子:偶尔它可以决定调整支持向量的大小,这使得it
指向现在无效的内存,并且由此产生的症状是崩溃。调用erase
首先会阻止数组的增长,但也会使it
无效,这会产生令人讨厌的副作用。
在这种情况下,正确的解决方案是覆盖迭代器的内容:
*it = it->add(*it, book);
或者您可以直接致电combine
:
it->combine(book);
或者您可以选择覆盖operator+=
并获得:
*it += book;