class 的方法正在执行但智能指针删除了对象时崩溃
Crash when method of class is executing but smart pointer deleted the object
我遇到了 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, ¬ifier);
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*
这是因为在从 RemoteSystemDisconnectionHandler::HandleDisconnection
调用方法 RemoteSystem::Close
时丢失了对 ReceiveDataEventHandler
的最后一个引用,因此,丢失了对 RemoteSystemDisconnectionHandler
的引用并删除了它目的。在 Close
方法并删除 类 RemoteSystemDisconnectionHandler
和 ReceiveDataEventHandler
的两个对象后,它 returns 到 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;
};
我遇到了 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, ¬ifier);
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*
这是因为在从 RemoteSystemDisconnectionHandler::HandleDisconnection
调用方法 RemoteSystem::Close
时丢失了对 ReceiveDataEventHandler
的最后一个引用,因此,丢失了对 RemoteSystemDisconnectionHandler
的引用并删除了它目的。在 Close
方法并删除 类 RemoteSystemDisconnectionHandler
和 ReceiveDataEventHandler
的两个对象后,它 returns 到 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;
};