【问题标题】:C++ Loop condition doesn't end the loop [closed]C ++循环条件不会结束循环[关闭]
【发布时间】:2013-08-09 17:27:00
【问题描述】:

我正在尝试将 Artemis 组件实体系统移植到 C++ 以学习一些东西。但是我遇到了一个奇怪的问题。

void addAll(ImmutableBagInterface<E>& items)
{
    for(auto i = 0u; i < items.size(); ++i)
    {
        add(items.get(i));
    }
}

即使有条件,这个 for 循环也会无限执行。 items.size() 通过使用 cout 打印返回一个有效值。我也尝试过 unsigned int 和 int 而不是 auto 迭代器但是它没有改变任何事情。我不知道发生了什么。

这是“ImmutableBag”的所有代码(它并不是真正不可变的,因为我使用的是向量,但是嘘,没人会知道:P)

#ifndef IMMUTABLEBAG_H
#define IMMUTABLEBAG_H

#include <vector>
#include <iostream>

namespace artemis
{
    template<class E>
    class ImmutableBagInterface
    {
    public:
        virtual ~ImmutableBagInterface(){};
        virtual E get(int index) = 0;
        virtual unsigned int size() = 0;
        virtual bool isEmpty() = 0;
        virtual bool contains(E e) = 0;
    };

    template<class E>
    class Bag : public ImmutableBagInterface<E>
    {
    private:
        std::vector<E> data;
        void init(int capacity)
        {
            data.reserve(capacity);
        }
    public:
        /**
        * Constructs an empty Bag with an initial capacity of 64.
        *
        */
        Bag()
        {
            init(64);
        }

        /**
        * Constructs an empty Bag with the specified initial capacity.
        *
        * @param capacity
        *            the initial capacity of Bag
        */
        Bag(int capacity)
        {
            init(capacity);
        }

        /**
        * Removes the element at the specified position in this Bag. does this by
        * overwriting it was last element then removing last element
        *
        * @param index
        *            the index of element to be removed
        * @return element that was removed from the Bag
        */
        E remove(int index)
        {
            E e = data.at(index);
            data.at(index) = data.back();
            data.pop_back();
            return e;
        }

        /**
        * Remove and return the last object in the bag.
        *
        * @return the last object in the bag, null if empty.
        */
        E removeLast()
        {
            if(!data.empty())
            {
                E e = data.back();
                data.pop_back();
                return e;
            }

            return nullptr;
        }


        /**
        * Removes the first occurrence of the specified element from this Bag, if
        * it is present. If the Bag does not contain the element, it is unchanged.
        * does this by overwriting it was last element then removing last element
        *
        * @param e
        *            element to be removed from this list, if present
        * @return <tt>true</tt> if this list contained the specified element
        */
        bool remove(E e)
        {
            for(auto i = 0u; i < data.size(); i++)
            {
                E e2 = data.at(i);
                if(e == e2)
                {
                    data.at(i) = data.back();
                    data.pop_back();
                    return true;
                }
            }
            return false;
        }

        /**
        * Check if bag contains this element.
        *
        * @param e
        * @return
        */
        bool contains(E e)
        {
            for(auto &v : data)
            {
                if( e == v )
                {
                    return true;
                }
            }
            return false;
        }

        /**
        * Removes from this Bag all of its elements that are contained in the
        * specified Bag.
        *
        * @param bag
        *            Bag containing elements to be removed from this Bag
        * @return {@code true} if this Bag changed as a result of the call
        */
        bool removeAll(ImmutableBagInterface<E>& bag)
        {
            bool modified = false;

            for(auto i = 0u; i < bag.size(); i++)
            {
                E e1 = bag.get(i);

                for(auto j = 0u; j < data.size(); j++)
                {
                    E e2 = data.at(j);

                    if(e1 == e2)
                    {
                        remove(j);
                        j--;
                        modified = true;
                        break;
                    }
                }
            }
            return modified;
        }

        /**
        * Returns the element at the specified position in Bag.
        *
        * @param index
        *            index of the element to return
        * @return the element at the specified position in bag
        */
        E get(int index)
        {
            return data.at(index);
        }

        const E get(int index) const
        {
            return data.at(index);
        }

        /**
         * Returns the number of elements in this bag.
         *
         * @return the number of elements in this bag
         */
        unsigned int size()
        {
            return data.size();
        }

        /**
         * Returns the number of elements the bag can hold without growing.
         *
         * @return the number of elements the bag can hold without growing.
         */
        int getCapacity()
        {
            return data.capacity();
        }


        /**
         * Returns true if this list contains no elements.
         *
         * @return true if this list contains no elements
         */
        bool isEmpty()
        {
            return data.empty();
        }

        /**
         * Adds the specified element to the end of this bag. if needed also
         * increases the capacity of the bag.
         *
         * @param e
         *            element to be added to this list
         */
        void add(E e)
        {
            data.push_back(e);
        }

        /**
         * Set element at specified index in the bag.
         *
         * @param index position of element
         * @param e the element
         */
        void set(unsigned int index, E e)
        {
            if(index >= data.size())
            {
                data.resize(index*2);
            }
            data.at(index) = e;
        }

        void grow()
        {
            int newCapacity = (data.capacity() * 3) / 2 + 1;
            grow(newCapacity);
        }

        void grow(int capacity)
        {
            data.resize(capacity);
        }

        void ensureCapacity(int index)
        {
            if(index >= data.capacity())
            {
                data.resize(index * 2);
            }
        }

        /**
         * Removes all of the elements from this bag. The bag will be empty after
         * this call returns.
         */
        void clear()
        {
            data.clear();
        }

        /**
         * Add all items into this bag.
         * @param added
         */
        void addAll(ImmutableBagInterface<E>& items)
        {
            for(auto i = 0u; i < items.size(); ++i)
            {
                add(items.get(i));
            }
        }
    };
}


#endif // IMMUTABLEBAG_H

这是发生问题的测试:

#include <iostream>
#include <string>
#include "ImmutableBag.h"

int main()
{
    using namespace artemis;
    Bag<std::string> bag;
    Bag<std::string> bag2;

    for(auto i = 0u; i < 20; i++)
    {
        bag2.add("Test");
    }

    bag2.add("Hello");
    bag2.add("World");

    bag.add("Hello");
    std::cout << bag.get(0) << std::endl;
    bag.add("World");
    std::cout << bag.get(1) << std::endl;

    for(auto i = 0u; i < bag2.size(); i++)
    {
        std::cout << bag2.get(i) << std::endl;
    }
    std::cout << "==========================" << std::endl;

    bag2.removeAll(bag); //Executes normally (Removes all items, which are identical to any of the items in bag, from bag2)

    for(auto i = 0u; i < bag2.size(); i++)
    {
        std::cout << bag2.get(i) << std::endl;
    }

    std::cout << "==========================" << std::endl;

    bag.addAll(bag2); //Infinite loop... NOPE I was an idiot and wrote bag.addAll(bag) instead of bag.addAll(bag2)as Mike Seymour and Thynk Apps pointed out 

    for(auto i = 0u; i < bag.size(); ++i)
    {
        std::cout << bag.get(i) << std::endl;
    }


    return 0;
}

【问题讨论】:

  • 你能把它设为SSCCE,这样我们就可以看到addAll 是如何被调用的。
  • 你不是想给自己添加一个包,是吗?如果您尝试这样做,addAll 的实现将永远循环。
  • @ShafikYaghmour 我添加了一个测试用例。
  • 来自您刚刚发布的代码。你正在做你不能做的事情。您正在将bag 添加到bag,这将使循环内的大小增加1 并无限循环。如果这是您想要做的,您可以通过在循环之前获取初始大小或将其作为第二个参数传入来将初始大小设置为循环条件。
  • @ThynkApps 是的......我是个白痴......我没有注意到我忘记添加'2'

标签: c++ for-loop infinite-loop


【解决方案1】:

我不知道您的 add() 函数在做什么,但您确实意识到,如果您在该循环内添加到您正在循环的容器中,您会将其大小增加 1,因此 for 循环可以(逻辑上)永不终止?不过,在那之前你很可能会耗尽内存。

【讨论】:

  • 除非items.size() 从零开始... =) 但可能是问题,是的
  • 只有在传入的项目列表等于您要添加到的容器时才会出现问题。我不知道你为什么要将所有项目添加到同一个容器中,但你可以通过设置 initialSize = items.size() 然后使用 i &lt; initialSize 作为循环条件来解决这个问题
  • @Michael 我知道循环条件不是当前容器的大小,而是传递给方法的容器的大小。因此,由于没有对该容器进行任何更改,因此在将所有项目添加到当前容器后,我应该可以顺利退出。 add() 方法只是包裹了底层向量的 push_back(),所以它只是将项目添加到包的末尾;
  • @mark & Thynk,我支持你 :)
  • @MrPlow,那么除非您在 get 函数中更改 i (并通过引用获取它),否则我看不出它如何永远循环。
猜你喜欢
  • 1970-01-01
  • 2012-02-21
  • 2021-04-08
  • 1970-01-01
  • 1970-01-01
  • 2016-07-31
  • 1970-01-01
  • 1970-01-01
  • 2021-11-25
相关资源
最近更新 更多