C++ 如何防止在多个向量中添加对象?
有些对象是C++ 如何防止在多个向量中添加对象?,c++,algorithm,design-patterns,vector,data-structures,C++,Algorithm,Design Patterns,Vector,Data Structures,有些对象是可绘制的,有些对象是可移动的 所有可移动的物体都可以移动。 我将所有可绘制对象存储在名为drawables的向量中,将可移动对象存储在名为movables的向量中。 我还有向量ships和Bullet,它们分别包含Ship和Bullet类型的对象。 Ship和Bullet都是可移动的 下面是这些类的结构: class Drawable { public: void draw(); }; class Movable : public Drawable { public:
可绘制的
,有些对象是可移动的
所有可移动的物体都可以移动。
我将所有可绘制对象存储在名为
drawables
的向量中,将可移动对象存储在名为movables
的向量中。
我还有向量ships
和Bullet
,它们分别包含Ship
和Bullet
类型的对象。
Ship
和Bullet
都是可移动的
下面是这些类的结构:
class Drawable {
public:
void draw();
};
class Movable : public Drawable {
public:
void move();
}
class Ship : public Movable {
public:
Ship();
}
class Bullet : public Movable {
public:
Bullet();
}
向量声明如下:
std::vector<Drawable*> drawables;
std::vector<Movable*> movables;
std::vector<Ship*> ships;
std::vector<Bullet*> bullets;
我创建了单独的drawables
和movables
向量,因为我有一个draw()
函数,它调用drawables
向量中所有对象的draw()
方法。类似地,我有一个move()
函数,它调用movables
向量中所有对象的move()
方法
我的问题是,如何更改结构以防止在不同的向量中添加相同的内容。一旦目标完成,我还需要从所有向量中删除对象。例如,一旦子弹击中某人或移出屏幕,我必须在所有三个向量中搜索后将其从向量
drawables
、movables
和bullets
中删除。似乎我没有使用正确的方法来存储这些对象。请提出一个替代方案
这似乎更像是一个软件工程问题,而不是一个编码问题。如果有必要,请将问题转移到其他论坛。既然所有
可移动的,船舶和子弹都是可绘制的
,为什么不将可绘制的
项目作为一个向量,并在其中添加所有不同的类?您将只有一个指向所有不同实例的指针,并且只有这些指针的一个向量。然而,这个解决方案可能需要将可绘制的变成一个抽象类。假设您使用的是一个相当现代的编译器,这正是存在的原因
问题是你不知道哪个向量拥有这个对象,所以你不知道该删除哪个shared_ptr
为您提供以下功能:它管理对象的生存期,并在销毁对对象的最后一次引用后将其删除
要创建新的装运
,可以执行以下操作:
auto ship = std::make_shared<Ship>();
drawables.push_back(ship);
movables.push_back(ship);
ships.push_back(ship);
auto ship=std::make_shared();
可抽出式。向后推(船);
动产。推回(船舶);
船。推回(船);
此时,ship
有4个引用(每个向量一个引用,ship
变量本身)。一旦它从所有三个向量中删除并且局部变量超出范围,它将自动被删除。如果您要维护一个包含(指向)特定类型的所有对象的容器,您可能需要采用RAII方法。将对象的构造函数添加到容器中,并将析构函数从容器中移除。您还需要确保没有其他内容会修改容器,因此它应该是类的私有(静态)成员,并使用公共方法提供只读访问
更好的是,将此逻辑移到它自己的类中,以便可以重用。这也将允许您现有的容器保持专注于它们当前所做的事情。他们只需要助手类类型的新数据成员
为了简化移除,我会考虑使用<代码>列表>代码>而不是<代码>向量<代码>。此外,可能值得使用
reference\u wrapper
而不是指针。指针可以有空值。虽然您可以记录容器将没有空指针,但是reference\u包装器
不需要额外的文档就可以传达这一点
为了让您开始,这里是一个可以使用的助手类模板的开始
template <class T>
class All {
using ListType = std::list< std::reference_wrapper<T> >;
private:
static ListType the_list;
// A list's iterators are rarely invalidated. For a vector, you would
// not store an iterator but instead search when removing from the_list.
typename ListType::iterator list_it;
public:
// Read-only access to the list.
static const ListType & list() { return the_list; }
// Construction
ListAll() : list_it(the_list.end()) {} // If this constructor is needed
explicit ListAll(T & data) : list_it(the_list.insert(the_list.end(), data)) {}
// Destruction
~ListAll() { if ( list_it != the_list.end() ) the_list.erase(list_it); }
// Rule of 5
// You should also define or delete the copy constructor, move constructor,
// copy assignment, and move assignment.
// If you need the default constructor, then you probably want a method like:
//void set(T & data);
};
template <class T>
typename All<T>::ListType All<T>::the_list{};
模板
全班{
使用ListType=std::list;
私人:
静态列表键入_列表;
//列表的迭代器很少会失效
//不存储迭代器,而是在从列表中删除时进行搜索。
typename ListType::迭代器列出它;
公众:
//对列表的只读访问。
static const ListType&list(){返回_list;}
//建筑
ListAll():如果需要此构造函数,请列出它(list.end()){}//
显式ListAll(T&data):list_it(the_list.insert(the_list.end(),data)){
//毁灭
~ListAll(){if(list_it!=the_list.end())the_list.erase(list_it);}
//第5条规则
//还应定义或删除复制构造函数、移动构造函数、,
//复制分配和移动分配。
//如果需要默认构造函数,则可能需要以下方法:
//无效集(T&data);
};
模板
typename All::ListType All::_列表{};
名字往往很难找到。我根据需要迭代的内容命名了这个模板,例如:All::list()
你能展示更多的代码吗?包括你的声明吗?@Galik添加了向量和类的声明查找实体组件系统,这是游戏事实上的标准结构。你的问题包含矛盾。在文本中,您声明“所有可绘制对象都是可移动的”,但代码表示相反:可移动
源于可绘制
,这意味着所有可移动对象都是可绘制的。至于实际问题:为什么首先有不同的向量?如果你的理由是好的,那么也许同样的理由也可以。(因为您存储的是指针而不是副本,所以开销不是很大。)有一些方法可以使向量更易于维护,但首先您需要确定您想要什么。可能有
template <class T>
class All {
using ListType = std::list< std::reference_wrapper<T> >;
private:
static ListType the_list;
// A list's iterators are rarely invalidated. For a vector, you would
// not store an iterator but instead search when removing from the_list.
typename ListType::iterator list_it;
public:
// Read-only access to the list.
static const ListType & list() { return the_list; }
// Construction
ListAll() : list_it(the_list.end()) {} // If this constructor is needed
explicit ListAll(T & data) : list_it(the_list.insert(the_list.end(), data)) {}
// Destruction
~ListAll() { if ( list_it != the_list.end() ) the_list.erase(list_it); }
// Rule of 5
// You should also define or delete the copy constructor, move constructor,
// copy assignment, and move assignment.
// If you need the default constructor, then you probably want a method like:
//void set(T & data);
};
template <class T>
typename All<T>::ListType All<T>::the_list{};