如果存储指针,std :: list比std :: vector更好吗?

时间:2010-11-13 14:08:10

标签: c++ stl

我通常避免使用std :: list,但是在我存储指针的情况下,使用std :: list会更有利,因为我可以随机插入指针而不必移动所有其他指针吗?在[{1}}

上存在哪些优点和缺点

由于

6 个答案:

答案 0 :(得分:9)

由于指针的复制构造很简单,因此这里的决定不是关于一个或另一个是否更适合存储指针,而是更好地满足您的需求。

如果你真的需要做很多随机插入(和删除?),那么list可以更好地工作,虽然这不是一个简单的决定 - 也许带有保留空间的vector会更好,即使这样。您是否希望list的每节点开销只是存储指针?在32位Windows上,list中每个条目的12个字节加上堆管理开销,每个条目总共20多个字节。这也无助于数据本地化随着时间的推移。同时,vector每个条目使用四个字节(再次使用32位)并保证将其元素存储在一个连续的块中。

除非将指针元素包装为某种类型的智能指针,否则必须以erase / clear /破坏容器的方式处理内存清理。另一种简化Some*内存管理的方法是Boost pointer containers

之一

有关listvectordeque的分析,另请参阅here。就个人而言,我越来越认为list在主流中没有用处。

答案 1 :(得分:3)

我认为它是 特别是指针 ,即使在随机位置有许多插入/删除,也应该考虑使用std::vector代替std::list。指针复制非常便宜(事实上,我希望我的标准库实现 使用CPU内在函数 来执行此操作),以便{{1}的更高位置对于随机插入/删除,数据可能远远超过std::vector在理论上更好的适应度。

无论如何,您必须测量您的应用程序(以及人工测试用例)才能确定。

答案 2 :(得分:1)

一般来说,您的首选应该是vector - 当您存储指针时也是如此。

将决定与C中的这个问题进行比较(-ish):我什么时候选择

struct linked_items {
  element      *item;
  linked_items *next;
};

   element* items[];  /* array of pointers to items */

有些情况,但首先检查您是否可以应用“更简单”的数据结构,即vector

答案 3 :(得分:0)

通常,当您需要一个存储某个东西的容器然后随机删除它时,最好的是set。要删除某些内容,您需要先找到它,对于向量和列表,O(n)和对于集合O(log(n))。如果找到则删除它是即时列表,但O(n)表示向量,而O(log(n))表示集合。

所以:

  • 如果你很少考虑vector 从中搜索或删除 容器;
  • 如果您很少在容器中搜索,请考虑list;
  • 另外考虑set

vector是最有效的内存和缓存。如果您知道元素的数量,那么使用reserve()可以使其100%的内存效率。

答案 4 :(得分:0)

基于基准测试研究,我更喜欢使用向量,除非有其他强大的用例来支持链表(带有一些开销信息)。但是以更好的方式处理插入和移除效率低下(平均而言)。

以下是我的想法:

vector<SomeObject*> vecSomeObjectPointers;
vector<size_t> vecInvalidPointerIndices;// could be zero size, if no objects are removed

创建/添加新的SomeObject元素:

void AddNewObject()
{
    SomeObject* ptrSomeObject = new SomeObject;
    ptrSomeObject->PopulateSomeObject(); // add any extra memory if needed by SomeObject members
    ptrSomeObject->DoAnyOtherWorkOnSomeObjectBeforeStoring();

    size_t TotalInValidIndices = vecInvalidPointerIndices.size();
    if(TotalInValidIndices > 0) 
    {
    //re-use the invalid location/index of vector to hold new object
    vecSomeObjectPointers[vecInvalidPointerIndices[TotalInValidIndices-1]] = ptrSomeObject;
    vecInvalidPointerIndices.pop_back();
    }
    else vecSomeObjectPointers.push_back(ptrSomeObject); // new Object pointer at the end
}

删除现有的SomeObject元素:

void DeleteAnExistingObject()
{
    //Find the index of the object to be deleted based on certain input criteria. Ex: value stored etc..
    SomeObject* ptrSomeObject;
    for(auto& itr=vecSomeObjectPointers.begin(); itr != vecSomeObjectPointers.end(); ++itr)
    {
        ptrSomeObject = itr;
        if(ptrSomeObject->SomeObjectDeletionCriteriaSatisfied())
        {
            // make sure to delete any extra memory allocated to SomeObject members
            delete ptrSomeObject; // re-claim allocated memory

            // just invalidate the pointer info rather deleting it from vector to save re-shuffling time
            itr = NULL; 

            //Store the corresponding index to be used for holding a new object to be inserted next time
            vecInvalidPointerIndices.push_back(itr - vecSomeObjectPointers.begin());
        }
    }
}

使用线性搜索时间处理向量的现有SomeObject元素:

void DoSomeWorkOnAnExistingObject()
{
    SomeObject* ptrSomeObject;
    for(auto& itr=vecSomeObjectPointers.begin(); itr != vecSomeObjectPointers.end(); ++itr)
    {
        if(itr == NULL) continue;
        //Do some work on object data to maintain it
        ptrSomeObject = itr;
    }
}

欢迎任何其他想法......

答案 5 :(得分:0)

我假设你问[std::list<Foo*>由于许多间接而导致真的很慢]

std::vector<Foo*> objects

Vs的

std::list<Foo> objects

std::vector

  • 快速遍历
  • 随机访问不同的Foo个对象
  • Foo可以是抽象的
  • 您需要手动delete您的对象
  • 如果不在最后,则插入缓慢

std::list

  • 无需手动delete个对象
  • 快速插入
  • 慢速遍历
  • 无法随机访问不同的Foo个对象
  • Foo不能是抽象的

编辑:

我意识到有一种情况是std :: vector不起作用,除非你的对象归其他人所有。考虑这个递归的事情

class Foo
    {
    public:
        ~Foo(); /**<Now this must be recursive, otherwise it would need std::stack, which results in potential exception from dtor!*/
    private:
        std::vector<Foo*> m_children;
    };