Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如果存储指针,std::list是否比std::vector更好?_C++_Stl - Fatal编程技术网

C++ 如果存储指针,std::list是否比std::vector更好?

C++ 如果存储指针,std::list是否比std::vector更好?,c++,stl,C++,Stl,我通常避免使用std::list,但在存储指针的情况下,使用std::list是否更有利,因为这样我就可以随机插入指针而不必移动所有其他指针?与std::vector 谢谢因为指针的复制构造很简单,所以这里的决定不是一个或另一个更适合存储指针,而是哪个更适合您的需要 如果你真的需要做大量的随机插入(和删除?),那么列表可以更好地工作,尽管这不是一个简单的决定-也许带保留空间的向量会更好,即使这样。是否希望列表的每个节点开销仅用于存储指针?在32位Windows上,列表中的每个条目有12个字节,加

我通常避免使用std::list,但在存储指针的情况下,使用std::list是否更有利,因为这样我就可以随机插入指针而不必移动所有其他指针?与
std::vector


谢谢

因为指针的复制构造很简单,所以这里的决定不是一个或另一个更适合存储指针,而是哪个更适合您的需要

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

无论哪种方式,您都必须处理容器销毁时的内存清理,除非您将指针元素包装为某种智能指针。另一种方法是简化
某些*
的内存管理


有关
列表
向量
deque
的一些分析,请参见。就我个人而言,我越来越认为
list
在主流中没有那么大用处。

一般来说,你的第一选择应该是
vector
——同样,当你存储指针时

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

结构链接项{ 要素*项目; 链接的项目*下一步; }; 结束

元素*项[];/*指向项的指针数组*/ ?

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

我认为它是特别是指针,在使用
std::vector
而不是
std::list
的情况下,即使在随机位置有许多插入/删除操作,也应该考虑使用
std::vector
。指针的复制成本非常低(事实上,我希望我的标准库实现使用CPU内部函数来实现这一点),因此
std::vector
数据的更高局部性可能远远超过
std::list
对于随机插入/删除的理论上更好的适用性


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

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

因此:

  • 如果您很少使用向量,请考虑
    vector
    从中搜索或删除 容器
  • 如果您很少在容器中搜索,请考虑
    列表
  • 否则,请考虑设置

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

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

我的想法是: 正在删除现有的SomeObject元素: 使用线性搜索时间处理向量的现有SomeObject元素:
欢迎您提出任何其他想法……

我想您可能会询问[
std::list
由于许多间接因素,速度会非常慢]

std::vector<Foo*> objects

真正找到答案的唯一方法是运行性能测试。另外,您可能会对容器是否拥有指针感兴趣。容器中会有多少指针?它们是一次插入还是在一段时间内插入?是否要从容器中删除一些指针?
列表
对于排序很重要并且在随机位置添加/删除元素非常有用。尤其是元素的范围。@Dialogicus:事实上,
list
之所以真正引人注目,是因为它是一个基于节点的容器,这意味着它的迭代器失效条件非常稀疏,与vector非常不同。也就是说,你可以将迭代器存储到列表的一个元素中,进行任意数量的插入/删除,只要你没有删除你存储的迭代器指向的元素,它仍然有效。我想他对
list
vector
@Inverse感兴趣:我不知道如何理解这个“如果存储指针,std::list比std::vector好吗?”无论是
list
还是
vector
都会避免复制构造。这就是我想问的问题,否则对于3k的人来说,这是一个相当基本的问题。 element* items[]; /* array of pointers to items */
vector<SomeObject*> vecSomeObjectPointers;
vector<size_t> vecInvalidPointerIndices;// could be zero size, if no objects are removed
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
}
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());
        }
    }
}
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;
    }
}
std::vector<Foo*> objects
std::list<Foo> objects
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;
    };