如何删除析构函数中的空指针?

Posted

技术标签:

【中文标题】如何删除析构函数中的空指针?【英文标题】:How to delete the void pointer in destructor? 【发布时间】:2017-02-09 11:14:43 【问题描述】:

我有这样的课:

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

和其他类的成员变量

vector<IncomingNetworkEvent> m_incomingNetworkArray;

当一个事件发生时,我创建IncomingNetworkEventsetItem(在类型转换为void* 之后,项目可能具有不同的类型)。创建IncomingNetworkEvent 后,我将它放在m_incomingNetworkArray .

所以有时我想清除m_incomingNetworkArray.clear()。它将调用IncomingNetworkEvent 的析构函数,但我必须删除void 的项目。因此,要删除它,我必须将类型转换回正确的类型。 一种解决方案是在析构函数中我根据事件对项目进行类型化(我知道哪个事件包含哪个类型)。但它会在析构函数中创建很多 switch case。

所以我想要这样的解决方案:

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);
;

所以我可以在不进行类型转换的情况下删除析构函数中的项目。但问题是我不能像这样声明传入的网络数组:

vector<IncomingNetworkEvent> m_incomingNetworkArray;

我必须将其声明为:

vector<IncomingNetworkEvent<someType>> m_incomingNetworkArray;

但这并不能解决我的问题,因为m_incomingNetworkArray 只能处理一种类型的IncomingNetworkEvent。 我怎样才能实现它?

【问题讨论】:

你能让item指向一个基类,然后所有的实际项目都是从那个基类派生的吗? 我知道哪个事件包含哪个类型。那么为什么 item 不是事件本身的一部分呢? 我有很多事件,其中一半不包含任何项目。所以如果我将项目保留为事件的一部分(即枚举),我必须创建很多类。我认为 Martin Boner 解决方案很好。 所以你根据IncomingNetworkEvent设置项目?所以我猜可能有一个 if-else 或 switch 构造,它从许多项目中选择一种类型并设置它。 是的,当我从服务器获取项目时,我设置了 IncomingNetworkEvent 并推送到 m_incomingNetworkArray。 【参考方案1】:

您可以创建一个ItemBase 类,从中创建所有项目。这个类将有一个虚拟析构函数。

现在不要将您的项目传递为void *,而是将其向下转换为ItemBase *,只要类型完整,您就可以delete

【讨论】:

【参考方案2】:

你可以这样做:

class IncomingNetworkEvent final 
private:
    // ...

    std::unique_ptr<void, void(*)(void*)> itemnullptr, [](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); ;
    
;

我假设该对象拥有ptr 的所有权,因为它也是被要求删除它的对象。 基本思想是您仍在擦除原始类型(因此使用void*),但在构造内部项目时设置了适当的析构函数。

要使用它,你可以简单地写:

IncomingNetworkEvent ev;
ev.setItem(new int);

剩下的就是扣除了。

如果你因为某种原因不能使用std:: unique_ptr和lambdas,你可以通过模板函数或者静态成员模板函数来达到同样的效果。

【讨论】:

以前我不能特别理解你的代码 std::unique_ptr)(void)> itemnullptr, [](void*); ,第二个论点,但现在我明白了。谢谢 @user1438832 你想让我在答案中添加更多细节吗?【参考方案3】:

您可以有一个非模板基类和一个模板派生类。然后事件向量保存指向基类的指针。

我还建议您在整个过程中使用std::unique_ptr 来指定所有权。

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;

【讨论】:

以上是关于如何删除析构函数中的空指针?的主要内容,如果未能解决你的问题,请参考以下文章

当类没有析构函数时,智能指针或作用域指针会删除对象吗

可扩展散列 - 析构函数 C++

为多态基类声明一个虚析构函数

为啥我在这里的析构函数中删除时创建了一个潜在的流浪指针?

虚析构函数与纯虚函数

在类的析构函数中删除数组