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

作者: 分类: 编程代码 时间:1970-01-01

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

Writing to existing Sales_data object in std::vector causes program to crash (C++)写入 std::vector 中的现有 Sales_data 对象会导致程序崩溃 (C++)

我正在阅读 Stanley Lippman 的 C++ Primer 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;
}

【问题讨论】:

标签: c++ c++11 vector containers


【解决方案1】:

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&amp; operator&gt;&gt;(std::istream &amp; is, Sales_data &amp; data)

【讨论】:

  • 谢谢 Caleth。
【解决方案2】:

在迭代集合时,您不能修改集合。 这以push_back 为例:有时它可以决定调整后备向量的大小,这使得it 指向现在无效的内存,由此产生的症状是崩溃。调用 erase 首先会阻止数组增长,但也会使 it 无效,这会产生烦人的副作用。

在这种情况下,正确的解决方案是在原地覆盖迭代器的内容:

*it = it->add(*it, book);

或者您也可以直接拨打combine

it->combine(book);

或者您可以选择覆盖 operator+= 并获取:

*it += book;

【讨论】:

  • 'now-uninitialised memory'——这不是说还有可用的内存吗?我更喜欢'无效内存'
  • 这样更好,是的。
  • 谢谢博杰。