在std::vector中写入现有的Sales_data对象会导致程序崩溃(C++)



我正在阅读和做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;

最新更新