简体   繁体   中英

How to check if object behind pointer is valid or was deleted?

I have two manager-classes ManagerA and ManagerB . Both of them hold a std::vector of pointers, that point to some objects. The problem is that a pointer from ManagerA can point to the same object obj like a pointer from ManagerB . Now, if I delete the obj from the vector of ManagerA , the program will crash, because ManagerB tries to access the object obj which is invalid now.

class ManagerA
{
public:
  std::vector<Object*> listA;
}

class ManagerB
{
public:
  std::vector<Object*> listB;
}

int main()
{
  ManagerA* A = new ManagerA();
  ManagerB* B = new ManagerB();
  Object* O = new Object();

  A->listA.push_back(O);
  B->listB.push_back(O);

  delete A.listA[0];
  B->listB[0]->doStuff(); // will crash here! How to avoid?

  retrun 0;
}

How can I avoid this? Is there a way to check in ManagerB , that the object, that is adressed by a pointer in listB is now invalid?

Is there a way to check in ManagerB, that the object, that is adressed by a pointer in listB is now invalid?

No.

How can I avoid this?

You will need to somehow track the validity/existence of the objects in some way.

There are many ways and design patterns to achieve this, depending on your needs.

If you want a generic solution, you may use shared ownership, for instance in the form of a reference-counted pointer, ie one that tracks how many people is pointing to the object, like std::shared_ptr in the standard library. This will give you basically what you get from other languages with a garbage collector.

However, note that it is usually a code smell going for shared ownership unless you have determined that there is no other better option.

Raw pointers themselves have no way of communicating to their owner(s) that they are being deleted. You'd need to add that into your code such that every place that may participate in shared ownership verifies if it is the last owner, and if so, then does the delete .

Alternatively, you could express the shared ownership using std::shared_ptr of the Object. The shared_ptr will manage the joint ownership of the object.

Additionally, if some things need a weak_ptr it also provides that facility. A "weak pointer" is a pointer to the object that is aware when the object has been destructed. Objects get destructed when there are no std::shared_ptr "strong pointers" to the object left.

Sometimes the Object needs to be self-aware that it is owned by a shared_ptr , and that is where inheriting from std::enable_shared_from_this is useful. (Personally, I think of std::enable_shared_from_this as being a bad pattern. But it is right in the standard. Just be careful about not making such things on the stack or merely new ing them up because then they aren't shared_ptr but the instance object doesn't know how it was created.)

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

using std::cout;
using std::vector;
using std::make_shared;
using std::shared_ptr;

struct Object final {
    unsigned int amIAlive = 0x600D600D;
    ~Object() { amIAlive = 0xDEADDEAD; }
    void doStuff() const;
};

void Object::doStuff() const {
    if (amIAlive == 0x600D600D) {
        cout << "Object is GOOD GOOD!\n";
    } else if (amIAlive == 0xDEADDEAD) {
        cout << "Object is DEAD DEAD and gone. Probably going to crash soon.\n";
    } else {
        cout << "Object is gone and overwritten. Probably going to crash soon.\n";
    }
}

class ManagerA final {
    vector<shared_ptr<Object>> listA;
public:
    void push_back(shared_ptr<Object> o) {
        listA.push_back(o);
    }
    void erase_at(size_t pos) {
        if (pos >= listA.size()) return; // No-op? throw?
        auto offset = static_cast<decltype(listA)::difference_type>(pos);
        listA.erase(listA.begin() + offset);
    }
};

class ManagerB final {
    vector<shared_ptr<Object>> listB;
public:
    void push_back(shared_ptr<Object> o) {
        listB.push_back(o);
    }
    void do_stuff_at(size_t pos) {
        if (pos >= listB.size()) return; // No-op? throw?
        listB[pos]->doStuff();
    }
};

int main() {
    auto A = ManagerA();
    auto B = ManagerB();
    auto O = make_shared<Object>();

    A.push_back(O);
    B.push_back(O);

    A.erase_at(0);
    B.do_stuff_at(0); // no more crash!
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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