假设我有一个通用的Object类和一个通用的List类。我想维护这些对象的列表。我应该将它们存储为List<Object>
还是List<Object*>
?
如果我使用List<Object>
,我的方法如下:
if(some_condition) {
Object obj;
myObjectList.append(obj);
}
我的list类只保留对该对象的引用,因此只要if语句终止,对象就会被销毁,并且我推送的对象变得无效。所以我最终做了类似的事情:
Object *obj = new Object;
myObjectList.append(*obj);
这样它就不会被破坏。但现在这些物体是不可取的,不是吗?因为现在它们被安全地存储在List作为对象,而不是指向对象的指针,所以我不能在它们上面调用delete ...或者当它们从列表中弹出时会自动被销毁吗?
在这种情况下,我应该使用List<Object*>
并在完成后将其从列表中删除,不是吗?
如此困惑......我确信我在某处有一个根本的误解。
答案 0 :(得分:6)
修改强>
正如评论boost::ptr_list中所提到的更好,因为它更有效,并且具有与std::list<boost::shared_ptr<T> >
相同的净效果。
修改强>
你提到你在评论中使用Qt。如果您使用&gt; = 4.5,则可以使用Qt的QList
和QSharedPointer
类,如下所示:
QList<QSharedPointer<Object> > object_list;
object_list.push_back(QSharedPointer<Object>(new Object));
我建议您使用std::list<>
。您也可能只想存储指向对象的指针,这样它们就不会一直被复制。
所以底线是:
假设您有一个名为Object
的班级。你应该这样做:
std::list<boost::shared_ptr<Object> > object_list;
object_list.push_back(new Object);
对于c ++ 11/14,不需要boost,只需使用标准的智能指针:
std::list<std::shared_ptr<Object>> object_list;
object_list.push_back(std::make_shared<Object>());
通过使用共享指针,当从列表中删除对象时,对象将自动清理(如果没有其他shared_ptr
S也指向它)。
你可以拥有list<Object *>
。但考虑到你的经验水平,我觉得你可以更容易地使用引用计数指针。
在这种情况下,我应该使用 列出并从中删除它们 列表,当我完成它们,不是吗?
是的,这是一个可行的选择,但我强烈建议智能指针以避免“......并从列表中删除它们......”完全步骤。
注意:强>
您提供的示例代码:
Object *obj = new Object;
myObjectList.append(*obj);
可能不是您想要的,这会在堆上创建一个新对象,它们会在列表中放置副本。如果之后没有delete obj
,那么由于原始指针不会自动delete
d,因此存在内存泄漏。
答案 1 :(得分:3)
在第一种情况下,复制对象并仅销毁原始对象。另一个实例保留在列表中。
在第二个版本中,您可以使用List析构函数删除存储的对象。
答案 2 :(得分:2)
与“所有”事物一样,没有一个答案 - 关于你想做什么的细节中的魔鬼,或者你的约束是什么。
如果对象是轻量级的并且不涉及深度复制,那么将小东西存储为副本会更有效。否则,智能指针的开销超过了保证。如果你是多态的,那么你可以使用模板化列表。
如果最小化复制并从模板实例中消除冗余代码更重要,那么使用智能共享指针列表。
或者使用裸指针列表,使用new / delete,并对指针所有权一丝不苟。
任何列表都会像列表一样,因此列表实现的选择取决于您未在此处枚举的因素。
答案 3 :(得分:1)
使用指针,如建议的那样。您使用的是“通用”对象,可能是基类,而list实际上包含一些派生到基础的派生对象 - 这意味着您必须将指针传递给最初创建的对象。否则你会剔除所有的多态性。
那是
class Base
{
public:
int x;
virtual int getData() const { return x; }
};
class Derived : public Base
{
public:
int y;
virtual int getData() const { return y; }
};
Derived obj1;
obj1.x = 1;
obj1.y = 2;
Base obj2 = obj1;
cout << obj2.getData();
这将打印1,因为obj2只是obj1的Base部分的副本,并且实际上是Base的实例。
答案 4 :(得分:1)
您可以使用List,然后当需要在x位置释放对象时,您可以使用类似
的内容void erase_object(list* l, int i) {
delete (*list)[x]
list -> removeObj((*list)[x]);
}