存储对象列表

时间:2009-08-21 03:10:48

标签: c++ pointers

假设我有一个通用的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*>并在完成后将其从列表中删除,不是吗?

如此困惑......我确信我在某处有一个根本的误解。

5 个答案:

答案 0 :(得分:6)

修改 正如评论boost::ptr_list中所提到的更好,因为它更有效,并且具有与std::list<boost::shared_ptr<T> >相同的净效果。


修改 你提到你在评论中使用Qt。如果您使用&gt; = 4.5,则可以使用Qt的QListQSharedPointer类,如下所示:

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]);
}