0

我正在尝试将 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;
}
4

1 回答 1

2

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

于 2013-08-09T17:28:43.470 回答