【问题标题】:How to delete a pointer after cast to void* and back如何在转换为 void* 并返回后删除指针
【发布时间】:2018-02-11 13:29:33
【问题描述】:

作为“消息”类的一部分,我尝试通过将不同类型的指针转​​换为 void* 指针并将它们保存在记住指针原始类型的包装类(“MsgData”)中来传输不同类型的指针。

例如一个布尔指针:

bool* data = new bool;
event.wheel.y < 0 ? *data = false : *data = true;
send("all", this, MSG_MOUSE_SCROLL, MsgData(data));

MsgData 的兼容构造函数被调用,变量被保存为我的消息类的成员:

MsgData():                        type_(NULLPTR),    data_(nullptr)     {}  // Null
MsgData(const bool* data):        type_(BOOL),       data_((void*)data) {}  // Bool
MsgData(const std::string* data): type_(STRING_STD), data_((void*)data) {}  // std::string
// ... etc.

我可以将指针转回并使用它们而不会出现任何错误,但是当我尝试删除它们时程序崩溃:

~MsgData() {
    switch (type_) {
    case (BOOL):
        if ((bool*)data_)
            delete (bool*)data_;
        break;
    // ... etc.
    }
}

bool 指针只是一个示例,所有其他类型和类也一样。 仅当我尝试删除指针时程序才会崩溃。将它们转换回原来的类型并使用它们不是问题。

我研究了这个问题,并在 StackOverflow 上发现了类似 this one 的问题,但是虽然将指针转换为 void* 并返回似乎被认为是不好的风格,但我找不到程序崩溃的原因。

【问题讨论】:

  • std::variant
  • 你的方法应该有效。如果没有minimal reproducible example,我们将无能为力。
  • 为了调试您的代码,我们需要查看它。
  • 如果你真的想调试它(这是不必要的,因为你应该用理智的东西代替它)打印出你newdelete的所有东西的类型和地址,然后检查记录不匹配的地方。或者,如果您使用的是 linux,请通过 -fsanitize=undefined,address 在运行时分析此类错误。
  • 您的代码可能会由于许多与您得出的问题完全无关的原因而崩溃。程序在delete 中可靠崩溃的事实可以用其他原因来解释,例如内存损坏。

标签: c++ pointers casting delete-operator void-pointers


【解决方案1】:

嗯,解决问题的更好方法是使用boost::variant(或std::variant)。一旦你开始使用它,所有删除和管理 typedata 的麻烦都会自动消失。您不是第一个遇到此类问题的人。许多其他人都面临过它,解决方案以boost::variantstd::variant 的形式提供。

无论如何,既然你自己开发了一个解决方案,我的建议是:在构造函数本身中构造一个适当的 deleter .. 或者只要你知道 type 是什么数据你的班级将持有:

MsgData()
 : type_(NULLPTR), data_(nullptr)     {} 

MsgData(const bool* data)
 : type_(BOOL), data_((void*)data), deleter_(&deleter<BOOL>) {}      

MsgData(const std::string* data)
 : type_(STRING_STD), data_((void*)data), deleter_(&deleter<std::string>) {}  

deleter_ 是成员:

std::function<void(void const*)>  deleter_;

deleter被定义为函数模板:

template<typename T>
void deleter(void const * data) {
   delete static_cast<T const *>(data);
}

一旦你有了这些,你的析构函数将如下所示:

~MsgData() {
   if (deleter_) {
      deleter_(data_);
   }
}

希望对您有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多