繁体   English   中英

如何从对象指针的向量中正确清除元素

[英]How to properly clean up elements from vectors of object pointers

我一直在研究动态分配,并在StackOverflow上遇到了这个问题:

取消分配存储在矢量中的对象?

提出的最高答案之一解释了在使用“指向对象的指针的向量”时如何手动管理内存:遍历向量调用delete的过程。

我的问题是关于如何删除向量的特定元素,而不是整个向量。 在下面的示例程序中,我有一个对象指针向量。 想象一下,这些对象的x变量会随着时间而递减...当对象的x值达到一个数字(假设为3)时,我希望删除该对象; 但是,我想始终通过对象的x值保持向量可排序。

问题是,当我对x值达到3的对象调用delete时,该对象将被删除,但那里仍然有一个指向随机内存位置的指针,向量的大小也保持不变。

当我遍历打印x值的向量时,我称为delete的元素仍然存在,但指向-53408995之类的值。 我如何摆脱矢量以及对象的指针元素?

由于在我的实际程序(不是下面的最小示例)中,向量会不断被其他更改X值等效项的因素连续排序,因此调用擦除不是一种选择。 我无法追踪他们的索引。 当我遍历向量以检查x值时,我想同时删除对象和指针元素。

例:

#include <iostream>
#include <vector>

class A
{
public:
    A(int i) { x = i; }
    int x;
};

int main()
{
    std::vector<A*> Vec;

    Vec.push_back(new A{ 5 });
    Vec.push_back(new A{ 4 });
    Vec.push_back(new A{ 3 });

    std::cout << "Size before = " << Vec.size() << std::endl; // 3

    for (auto& a : Vec)
    {
        std::cout << a->x << std::endl;

        if (a->x == 3) { delete a; }
    }

    std::cout << "Size after = " << Vec.size() << std::endl; // Still 3!

    for (auto& a : Vec)
    {
        std::cout << a->x << std::endl; // Prints 5, 4 and a random memory location like -34528374
    }

    return 0;
}

您在注释中提到对象将具有指向它们的其他指针。 对我来说,这听起来像std::shared_ptr<A> 这样,您可以拥有其他指向A对象的指针,而不会出现内存泄漏问题。 std::shared_ptr性能成本很小(!),但您现在不必担心。) 另外,我更改了您的段落以从向量中删除/擦除您的元素。 请注意,如果还有其他实例向其保留std::shared_ptr<A>副本,则A对象仍然存在(但这是一件好事)。

这是代码:

#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>

class A
{
public:
    A(int i) { x = i; }
    int x;
};

int main()
{
    std::vector<std::shared_ptr<A>> Vec;
    Vec.emplace_back(std::make_shared<A>(5));
    Vec.emplace_back(std::make_shared<A>(4));
    Vec.emplace_back(std::make_shared<A>(3));

    std::cout << "Size before = " << Vec.size() << std::endl;

    Vec.erase(
        std::remove_if(std::begin(Vec),std::end(Vec), [](auto&& ptr){ return ptr->x == 3;}),
        std::end(Vec));

    std::cout << "Size after = " << Vec.size() << std::endl;
    for (auto&& a : Vec)
    {
        std::cout << a->x << std::endl;
    }

    return 0;
}

在这种情况下,您必须使用std :: list容器

#include <iostream>
#include <list>

class A
{
public:
    A(int i) { x = i; }
    int x;
};

int main()
{
    std::list<A*> Vec;

    Vec.push_back(new A{ 5 });
    Vec.push_back(new A{ 4 });
    Vec.push_back(new A{ 3 });

    std::cout << "Size before = " << Vec.size() << std::endl;

    for (auto& a : Vec)
    {
        std::cout << a->x << std::endl;
    }

    Vec.remove_if([](A* a){
        bool status = (a->x == 3);
        if(status){
            delete a;
            return true;
        }else{
            return false;
        }
    });

    std::cout << "Size after = " << Vec.size() << std::endl;

    for (auto& a : Vec)
    {
        std::cout << a->x << std::endl;
    }

    return 0;
}

输出:

Size before = 3
5
4
3
Size after = 2
5
4

我重写您的代码,添加了一些改进

#include <iostream>
#include <list>

class A
{
public:
    A(const int& i):x(i) {} // so X is assigned to i in construction ( more efficient )
    int get_x() const {return x;}
private:
    int x; // x have to be private ( good practice )
};

int main()
{
    std::list<A> List; // A instead of A* so the process of construction / destruction is handled automatically

    List.emplace_back(5); // append element and constructed at the same time
    List.emplace_back(4); // see std::list for more details
    List.emplace_back(3);

    std::cout << "Size before = " << List.size() << std::endl;

    for (auto& a : List)
    {
        std::cout << a.get_x() << std::endl;
    }

    List.remove_if([](A a){ return a.get_x() == 3;});

    std::cout << "Size after = " << List.size() << std::endl;

    for (auto& a : List)
    {
        std::cout << a.get_x() << std::endl;
    }
    return 0;
}
std::vector<std::unique_ptr<A>> vec;

这将处理正常的删除并通过异常退出。

在研究了迭代器之后,我还提出了一个使用原始指针的答案:

for (std::vector<A*>::iterator it = Vec1.begin(); it != Vec1.end(); )
{
    if ((*it)->x == 3)
    {
        delete * it;
        it = Vec1.erase(it);
    }
    else 
    {
        ++it;
    }
}

我会保留phön的帖子作为答案,因为如果有的话,应该始终首选智能指针而不是原始指针。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM