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