代码之家  ›  专栏  ›  技术社区  ›  KrystianCoder2

c中std::vector的怪异行为++

  •  -1
  • KrystianCoder2  · 技术社区  · 1 年前

    为什么这不起作用?

    这是一个基本的库存系统。 inventory std::vector<Item> Item 是具有的结构 int quantity std::string name .

    struct Item
    {
        int quantity;
        std::string name;
    };
    
    void AddItemToInventory(std::string itemName)
    {
        Item i;
        i.name = itemName;
        if(inventory.empty())
        {
            i.quantity = 1;
            inventory.push_back(i);
            std::cout << "EMPTY\n";
        }
        else
        {
            for (auto& item : inventory)
            {
                if(i.name == item.name)
                {
                    i.quantity = item.quantity + 1;
                }
                else
                {
                    i.quantity = 1;
                }
                inventory.push_back(i);
            }
        }
    }
    

    我本以为它会起作用。当它是空的时,添加一个到 库存 属于 name ,当它不为空时,只需添加另一个。如果存在,只需将1添加到 quantity .

    2 回复  |  直到 1 年前
        1
  •  3
  •   Remy Lebeau    1 年前

    你不需要第一个 empty() 检查,循环将处理一个空 vector 很好。

    你的循环是错误的,因为它正在推动一个新的 Item 进入 矢量 在每次迭代(即 未定义的行为 对于 range-for

    不要打电话 push_back() 完全在循环内部。第一个循环通过 矢量 寻找想要的 项目 。如果找到了,您可以更新它并停止循环。如果找不到,请添加 之后 循环已经结束。

    试试这个:

    void AddItemToInventory(std::string itemName)
    {
        for (auto& item : inventory)
        {
            if (item.name == itemName)
            {
                item.quantity += 1;
                std::cout << "UPDATED\n";
                return;
            }
        }
    
        Item newItem;
        newItem.name = itemName;
        newItem.quantity = 1;
    
        inventory.push_back(newItem);
    
        std::cout << "ADDED\n";
    }
    

    更新: 也就是说,考虑完全取消手动循环并使用 std::find_if() 相反,例如:

    void AddItemToInventory(std::string itemName)
    {
        auto found = std::find_if(
            inventory.begin(), inventory.end(), 
            [&](const Item &item){ return item.name == itemName; }
        );
    
        if (found != inventory.end())
        {
            found->quantity += 1;
            std::cout << "UPDATED\n";
        }
        else 
        {
            Item newItem;
            newItem.name = itemName;
            newItem.quantity = 1;
    
            inventory.push_back(newItem);
    
            std::cout << "ADDED\n";
        }
    }
    
        2
  •  1
  •   wohlstad    1 年前

    正如另一个答案中所解释的,在基于范围的迭代过程中,不能将元素添加到容器中(实际上应该在循环之后添加它)。

    然而,在这种情况下,您可以完全避免循环,并使用 std::find_if 来自 <algorithm> 头球

    它将搜索容器并向项返回迭代器(如果找到),或者 end 迭代器,如果不是。

    A. lambda 用于检查项目名称是否与容器中项目的名称匹配。

    如下所示:

    #include <algorithm>   // required for std::find_if
    
    void AddItemToInventory(std::string const & itemName)
    {
        auto it = std::find_if(inventory.begin(), 
                               inventory.end(), 
                               [&itemName](Item const& item) { return item.name == itemName; });
        if (it == inventory.end())
        {
            Item i;
            i.name = itemName;
            i.quantity = 1;
            inventory.push_back(i);
            std::cout << "Added\n";
        }
        else
        {
            it->quantity += 1;
            std::cout << "Updated\n";
        }
    }
    

    注意,我变了 itemName 成为 const& 在将其传递给时避免非种子副本 AddItemToInventory .

    Demo - Godbolt .