简体   繁体   中英

How to delete the void pointer in destructor?

I have a class like this:

class IncomingNetworkEvent {
private:
    IncomingNetworkEventForGame event;
    void* item;
public:
    IncomingNetworkEvent();
    ~IncomingNetworkEvent();
    IncomingNetworkEventForGame getEvent();
    void setEvent(IncomingNetworkEventForGame event);
    void* getItem();
    void setItem (void* item);
};

And a member variable in other class

vector<IncomingNetworkEvent> m_incomingNetworkArray;

When an event comes I create the IncomingNetworkEvent and setItem (item may be of different type based on event after type casting to void* ).After creating the IncomingNetworkEvent I put it on the m_incomingNetworkArray .

So there is a case when I want to clear the m_incomingNetworkArray.clear() . It will call the destructor of IncomingNetworkEvent but I have to delete item which is void . So to delete it I have to typecast back to proper type.
One solution will be in destructor I typecase the item according to event (I know which event contains which type). But it will create lot of switch case in the destructor.

So I wanted a solution like this:

template <class T>
class IncomingNetworkEvent {
private:
    IncomingNetworkEventForGame event;
    T* item;
public:
    IncomingNetworkEvent();
    ~IncomingNetworkEvent();
    IncomingNetworkEventForGame getEvent();
    void setEvent(IncomingNetworkEventForGame event);
    T* getItem();
    void setItem (T* item);
};

So I can delete item in the destructor without typecasting. But the problem is I cannot declare incoming network array like:

vector<IncomingNetworkEvent> m_incomingNetworkArray;

I have to declare it as:

vector<IncomingNetworkEvent<someType>> m_incomingNetworkArray;

But this will not solve my problem as m_incomingNetworkArray will can process only IncomingNetworkEvent of one type.
How can I achieve it?

You can create an ItemBase class from which all items are created. This class will have a virtual destructor.

Now instead of passing your Item as void * , let it downcast to ItemBase * and you would be able to delete it as long as the type is complete.

You can do something like this:

class IncomingNetworkEvent final {
private:
    // ...

    std::unique_ptr<void, void(*)(void*)> item{nullptr, [](void*){}};

public:
    // ...

    void* getItem() { return item.get(); }

    template<typename T>
    void setItem (T* ptr) {
        item = std::unique_ptr<void, void(*)(void*)>{ptr, [](void *ptr){ delete static_cast<T*>(ptr); }};
    }
};

I assumed that the object takes the ownership of ptr , for it is also the one demanded to delete it.
The basic idea is that you are still erasing the original type (thus using void* ), but you set a proper destructor when you construct the internal item.

To use it, you can simply write:

IncomingNetworkEvent ev;
ev.setItem(new int);

Deduction will do the rest.

If you can't use std:: unique_ptr and lambdas for some reason, you can achieve the same result by means of a template function or static member template function.

You can have a non-template base and a template derived class. The events vector then holds pointers to the base class.

I also suggest that you use std::unique_ptr to designate ownership throughout.

class IncomingNetworkEventBase {
private:
    IncomingNetworkEventForGame event;
public:
    virtual ~IncomingNetworkEventBase() = default;
    IncomingNetworkEventForGame getEvent();
    void setEvent(IncomingNetworkEventForGame event);
};

template <class T>
class IncomingNetworkEvent : public IncomingNetworkEventBase{
private:
    std::unique_ptr<T> m_item;
public:
    T* getItem() { return m_item.get(); }
    void setItem (std::unique_ptr<T> item) { m_item = std::move(item); }
};

vector<std::unique_ptr<IncomingNetworkEventBase>> m_incomingNetworkArray;

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