【问题标题】:Can i delete and erase the list of pointers like below我可以像下面这样删除和擦除指针列表吗
【发布时间】:2016-03-18 10:42:31
【问题描述】:

这是我程序中的代码

    #include <iostream>
    #include <string>
    #include <list>

    int main()
    {
        std::list<int *> list;
       //populating the list with some pointers
        for(int i =0;i<5;i++)
        {
            int *p = new int(i);
            list.push_back(p);
        }
        //want to delete and erase the contents of the above list
        for(std::list<int *>::iterator iter = list.begin(); iter != list.end(); iter++)
        {
           delete(*iter);
           list.erase(--iter);
        }  
        // trying to print the list contents
        for(std::list<int *>::iterator iter = list.begin(); iter != list.end(); iter++)
        {
           std::cout<<*iter<<std::endl;
        }

    }

这是一个正确的方法吗?

【问题讨论】:

    标签: c++ list pointers iterator


    【解决方案1】:

    首先你的方法不仅错误而且很糟糕!!!这是因为您要删除列表中的对象,然后使用 std::cout 打印它们,这会导致 UB。其次,您在遍历它们的迭代器上使用erase。一旦你删除了一个迭代器,你就会使它和对它的引用无效。所以再次使用invalid iterators会导致UB。

    接下来,您无需删除容器中保存的每个元素。容器在RAII principle 上工作,因此会自动释放它们的资源。所以你的擦除代码减少到:-

    for (auto itr = l.begin(); itr!=l.end(); ++itr)
        {
            delete  *itr;
        }
    

    在 C++ 中使用迭代器时需要非常小心,因为无论它们多么有用,对于初学者来说它们都不是那么容易使用。但随着您对它们的了解,您会发现使用它们很舒服,并且可能也会喜欢它们!

    【讨论】:

    • 其实最后的循环并没有什么问题。它应该什么都不打印(因为列表是空的) - 如果早期的代码按预期工作。是早期的代码被破坏了。
    • 我认为关键是他希望不依赖析构函数而丢弃列表的内容。所以你需要一个 list.clear() 在你的循环之后。
    • No @MartinBonner 打印删除的元素是 UB。它不会在您的系统中打印任何内容,它可能会在另一个系统中爆发,这意味着您无法评论它的行为方式。另外 clear 函数不是必需的,std::list 的析构函数会处理所有事情,所以你多写一行,浪费你的时间和运行时间
    • 打印删除的元素当然是UB。我的观点是,如果您已成功擦除元素,那么循环将什么也不做(因为列表为空),因此您将无法访问已删除的元素 - 所以没有 UB。关于 clear 的要点是我假设这是一个简单的示例,并且应该在 clear 之后和析构函数(例如打印循环)之前有另一大块代码,它重用“list”变量(但显然不是我们刚刚删除的元素)。
    • 如果list.clear()是list被销毁前最后一次使用,那么是的,完全是多余的。
    【解决方案2】:

    在迭代列表时修改列表是一个非常糟糕的主意。

    此外,每次通过列表时,您都会减少 iter,然后在 for 语句中增加它 - 所以它永远不会移动。

    我认为您需要做的是遍历循环删除指针,然后清除整个列表。

        for (const auto p: list)
            delete p;
        p.clear();
    

    更好的是,让列表成为 unique_ptrs 的列表,而且更简单:

        std::list<std::unique_ptr<int>> list;
        //populating the list with some pointers
        for(int i =0;i<5;i++)
        {
            list.push_back( std::make_unique( i ) );
        }
        //want to delete and erase the contents of the above list
        list.clear();  // unique_ptr destructor will delete the memory.
    

    记住一句口头禅:如果可以避免,就不要写一个赤裸裸的新东西。

    【讨论】:

    • 修改迭代器也是个极坏的主意。
    • 除非你修改它,否则很难通过循环!
    • 我的意思是,操纵迭代器本身是一个非常糟糕的主意,就像操纵你正在迭代的东西(比如删除元素)是一个超级糟糕的主意一样。好多了对副本进行操作。
    • 是的!抱歉,我知道你的意思。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    • 2021-05-07
    • 1970-01-01
    • 2012-06-19
    • 2017-04-05
    • 1970-01-01
    相关资源
    最近更新 更多