我正在閱讀和做 Stanley Lippman 的 C Primer Ed.5 中的練習。
我的代碼存在以下問題:當我更新 中的現有Sales_data物件時std::vector<Sales_data> vec;,程式崩潰。
為了克服這個問題,我洗掉了現有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;
}
uj5u.com熱心網友回復:
vec.erase(it);invalidates 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).
uj5u.com熱心網友回復:
迭代時不允許修改集合。例如push_back:有時它可以決定調整支持向量的大小,這會it指向現在無效的記憶體,結果是崩潰。erase首先呼叫可防止陣列增長,但也會使it具有惱人副作用的無效。
在這種情況下,正確的解決方案是就地覆寫迭代器的內容:
*it = it->add(*it, book);
或者你可以combine直接呼叫:
it->combine(book);
或者您可以選擇覆寫operator =并獲得:
*it = book;
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/378904.html
