微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

当类的方法正在执行但智能指针删除了对象时崩溃

如何解决当类的方法正在执行但智能指针删除了对象时崩溃

我遇到了 C++ 内存管理和智能指针的问题。 我有一个代码可以向您展示问题:

#include <memory>

class Closeable
{
 public:
  virtual void Close() = 0;
};

class disconnectionHandler
{
 public:
  virtual void Handledisconnection() = 0;
};

class EventHandler
{
 public:
  virtual void HandleEvent() = 0;
};

class Notifier
{
 public:
  virtual void Ondisconnection() = 0;
};

class RemoteSystem : public Closeable
{
 public:
  void SetReceiveDataEventHandler(const std::shared_ptr<EventHandler>& receive_data_event_handler) {
    this->receive_data_event_handler_ = receive_data_event_handler;
  }

  void Close() override { this->receive_data_event_handler_ = nullptr; }

  // In this example to simplify the code I just call this method from the main function.
  void OnDataReceived() { this->receive_data_event_handler_->HandleEvent(); }

 private:
  std::shared_ptr<EventHandler> receive_data_event_handler_;
};

class ReceiveDataEventHandler : public EventHandler
{
 public:
  explicit ReceiveDataEventHandler(const std::shared_ptr<disconnectionHandler>& disconnection_handler)
      : disconnection_handler_(disconnection_handler) {}

  void HandleEvent() override {
    // Some code of receiving data.
    // But we can find out that connection was closed and we must call the disconnection handler.
    if (this->IsConnectionClosed()) {
      this->disconnection_handler_->Handledisconnection();
      return;
    }
    // Some other stuff..
  }

 private:
  [[nodiscard]] bool IsConnectionClosed() const {
    // In the example code I just return true.
    return true;
  }

 private:
  const std::shared_ptr<disconnectionHandler> disconnection_handler_;
};

class RemoteSystemdisconnectionHandler : public disconnectionHandler
{
 public:
  explicit RemoteSystemdisconnectionHandler(const std::shared_ptr<Closeable>& closeable_remote_system,Notifier* notifier)
      : closeable_remote_system_(closeable_remote_system),notifier_(notifier) {}

  ~RemoteSystemdisconnectionHandler() { printf("Destructed.\n"); }

  void Handledisconnection() override {
    this->closeable_remote_system_->Close();
    printf("Closed.\n");
    this->notifier_->Ondisconnection();
    printf("Notified.\n");
  }

 private:
  const std::shared_ptr<Closeable> closeable_remote_system_;
  Notifier* const notifier_;
};

class ClientNotifier : public Notifier
{
 public:
  void Ondisconnection() override { printf("disconnected.\n"); }
};

int main() {
  ClientNotifier notifier;

  auto remote_system = std::make_shared<RemoteSystem>();

  {
    // Scope for losing references in the main function after SetReceiveDataEventHandler.
    auto disconnection_handler = std::make_shared<RemoteSystemdisconnectionHandler>(remote_system,&notifier);
    auto receive_data_event_handler = std::make_shared<ReceiveDataEventHandler>(disconnection_handler);
    remote_system->SetReceiveDataEventHandler(receive_data_event_handler);
  }

  // Only in the example.
  remote_system->OnDataReceived();

  return 0;
}

您也可以运行此代码。在本示例中,程序在 this->notifier_->Ondisconnection() 行崩溃。程序输出

Destructed.
Closed.
*crash*

发生这种情况是因为从 ReceiveDataEventHandler 调用方法 RemoteSystem::Close 时丢失了对 RemoteSystemdisconnectionHandler::Handledisconnection 的最后一个引用,因此丢失了对 RemoteSystemdisconnectionHandler 的引用并删除了此对象。在 Close 方法删除RemoteSystemdisconnectionHandlerReceiveDataEventHandler 的两个对象之后,它返回到 RemoteSystemdisconnectionHandler::Handledisconnection 方法并打印“Closed”。到输出,但由于对象已经被删除,下一行发生错误,因为现在 this删除并且对它的任何访问都会发生内存异常。 我还尝试在 Java 上重写此代码,它运行良好,与 C++ 不同。 所以想请教各位C++社区有没有解决这个问题的方法? 我认为 C++ 在内存管理方面没有问题,因为智能指针存在,但显然我错了。 希望得到您的帮助! 提前致谢!

解决方法

一个简单的解决方案是在调用 shared_ptr 的方法之前复制它:

    void OnDataReceived()
    { 
        auto temp = this->receive_data_event_handler_;
        if (temp)
        {
            temp->HandleEvent();
        }
    }

temp 将使指针保持活动状态,直到方法调用完成。

但是请注意,如果您在实际代码中使用多个线程,则 std::shared_ptr 不是线程安全的,因此您需要引入互斥锁来保护对 receive_data_event_handler_ 的访问:

class RemoteSystem : public Closeable
{
public:
    void SetReceiveDataEventHandler(const std::shared_ptr<EventHandler>& receive_data_event_handler) {
        this->receive_data_event_handler_ = receive_data_event_handler;
    }

    void Close() override 
    { 
        std::unique_lock lock(mutex);
        this->receive_data_event_handler_ = nullptr;
    }

    // In this example to simplify the code I just call this method from the main function.
    void OnDataReceived()
    { 
        std::shared_ptr<EventHandler> temp;
        {
            std::unique_lock lock(mutex);
            temp = this->receive_data_event_handler_;
        }
        if (temp)
        {
            temp->HandleEvent();
        }
    }

private:
    std::shared_ptr<EventHandler> receive_data_event_handler_;
    std::mutex mutex;
};

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。