简体   繁体   English

c ++删除不存在的指针

[英]c++ deleting non-existing pointers

class C {

public:
    std::vector<C*> list;
    int value;

    C(int value,  C* parent)
    {
        this->value = value;

        if(parent)
        {
            parent->registerChild(this);
        }
    }

    void registerChild(C* child)
    {
        this->list.push_back(child);
    }

    ~C()
    {
        for(std::vector<C*>::iterator it = list.begin(); it != list.end(); ++it)
        {
            if( (*it))
            {
                delete (*it);
            }
        }
    }
};

This is for a GUI project. 这是一个GUI项目。 A child class that has a parent, must notify parent class of it so that when the parent class gets deleted, all of its children should be deleted too. 具有父级的子类必须通知它的父类,以便在删除父类时,也应删除其所有子级。

C* main = new C(100, 0);

C* child1 = new C(250, main);
C* child2 = new C(450, main);

delete main;

^ everything works as expected - main is deleted along with child1 and child2. ^一切按预期工作 - main与child1和child2一起删除。

C* main = new C(100, 0);

C* child1 = new C(250, main);
C* child2 = new C(450, main);

delete child1;

delete main; // windows error

If I decided to get rid of child1 first and then sometime later decided to delete main, I get a windows error that is traced back to vector loop where apparently delete tries to delete a now non-existent pointer. 如果我决定首先摆脱child1,然后稍后决定删除main,我会得到一个Windows错误,可以追溯到矢量循环,显然删除尝试删除现在不存在的指针。 I would have thought that if( (*it)) would return false for a pointer that doesn't exist anymore. 我原以为if((* it))会为不再存在的指针返回false。

What can I do here? 我能在这做什么?

EDIT: This appears to work flawlessly 编辑:这似乎完美无缺

class C {

    typedef std::vector<C*> cList;

public:
    std::vector<C*> list;
    int value;
    C* parent;

    C(int value,  C* parent)
    {
        this->value = value;
        this->parent = parent;

        if(parent)
        {
            parent->registerChild(this);
        }
    }

    void registerChild(C* child)
    {
        this->list.push_back(child);
    }

    void removeChild(C* child)
    {
        cList::iterator it = std::find(list.begin(), list.end(), child);

        if(it != list.end())
        {
            list.erase(it);
        }
    }

    ~C()
    {
        if(this->parent)
        {
            // this child is being removed - notify parent and remove this from its child_list
            this->parent->removeChild(this);
        }

        cList::iterator it = list.begin();

        while(it != list.end())
        {
            delete (*it);

            // find a new beginning
            it = list.begin();
        };
    }
};

When you call delete main , it will call delete on its children. 当你调用delete main ,它会在其子delete上调用delete child1 is one of them. child1就是其中之一。 So you are calling delete on the same memory address twice. 所以你在同一个内存地址上调用delete两次。 And that is undefined behaviour . 这是未定义的行为

I would have thought that if( (*it)) would return false for a pointer that doesn't exist anymore. 我原以为if( (*it))会为不再存在的指针返回false。

No, there is no mechanism for one pointer to know that the object it points to has been deleted via another pointer. 不,没有机制让一个指针知道它指向的对象已经通过另一个指针删除了。

What can I do here? 我能在这做什么?

Make sure only one entity is responsible for managing dynamically allocated objects. 确保只有一个实体负责管理动态分配的对象。

It is a semi-widely missconception that a pointer is set to NULL when the memory it points to is deleted. 这是一个半广泛的错误概念,当指针被指向的内存被删除时,指针被设置为NULL。 It is not. 它不是。 Also, it is safe to delete NULL so checking whether a pointer is not NULL before deleting it is not necessary (off topic...). 此外,删除NULL是安全的,因此在删除指针之前检查指针是否为NULL是不必要的(关闭主题...)。

There's nothing magic about pointers. 指针没有什么神奇之处。 They are just (generally speaking) integers of machine word width which can be used to refer to specific memory addresses. 它们(通常是)机器字宽的整数,可用于指代特定的存储器地址。 There's no magic that NULLs that integer when the memory area it mentions is no longer owned by your program. 当它提到的内存区域不再由您的程序拥有时,没有任何魔法可以使整数为NULL。

It's a bad idea to deal with raw pointers like this. 处理像这样的原始指针是一个坏主意。 People are too easily confused by who is responsible for managing the memory pointed to. 人们很容易被谁负责管理指向的内存所迷惑。

Look into std::unique_ptr and std::shared_ptr ( http://en.cppreference.com/w/cpp/memory ). 查看std :: unique_ptr和std :: shared_ptr( http://en.cppreference.com/w/cpp/memory )。

Consider keeping the parent pointer as a member of the class, adding a deregister member function. 考虑将父指针保持为类的成员,添加注销成员函数。 Then in the destructor of the class, have the object deregister itself from the parent. 然后在类的析构函数中,让对象从父对象中取消注册。 You'll need to change how you manage the child window list. 您需要更改管理子窗口列表的方式。

Also, the names of your class member variables really should be more descriptive. 此外,类成员变量的名称实际上应该更具描述性。 list doesn't tell us much. list并没有告诉我们多少。 Consider a name like children or child_list . 考虑像childrenchild_list这样的名称。

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

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