我有一个EventEmitter和一个EventHandler对象。将EventHandler*添加到EventEmitter的处理程序矢量中。这使得任何扩展处理程序的对象都可以通过公共接口通过事件发射器进行调用。
现在,当EventHandler决定在程序员没有意识到的情况下进行析构(通常是复制ctors和=运算符),并且EventEmitter最终会调用它,从而导致程序崩溃时,问题就会出现。
第一个想法是为EventHandler提供对其发射器的引用,这样它就可以在销毁过程中调用分离函数。但是,现在我们必须考虑到事件发射器决定死亡,在此之后的任何时间都可以调用处理程序析构函数。我们只是把问题向前推进了。
这听起来像是一个非常常见的指针问题,我不怀疑在C++11或boost中已经解决了这个问题,但我无法访问这两个问题。在C++ 98中,有没有智能指针系统的通用布局可以解决这个问题?
一些用于说明的代码
// Example program
#include <iostream>
#include <string>
#include <vector>
class Handler {
public:
std::string msg;
Handler(std::string msg):msg(msg){}
void Run(){
std::cout << msg << std::endl;
}
};
class Emitter {
public:
std::vector<Handler*> handlers;
void Attach(Handler *handler){
handlers.push_back(handler);
}
void Detach(Handler *handler){
// find the handler, remove
}
void Emit(){
for(size_t i = 0; i < handlers.size(); i++){
std::cout << "Calling a handler" << std::endl;
handlers[i]->Run();
}
}
};
int main()
{
Emitter emitter;
Handler handler1("handler1");
emitter.Attach(&handler1);
// Uh oh, attached, then out of scope
{
Handler handler2("handler2");
emitter.Attach(&handler2);
}
emitter.Emit();
}输出
Calling a handler
handler1
Calling a handler 发布于 2020-08-14 14:41:08
好的,这就是我想出来的。具有引用计数的共享指针。两个对象共享对这个指针的访问。当它们死亡时,如果引用计数降低到0,它们将删除共享指针。这种情况应该不会多次发生。至少在我的测试中。
// Example program
#include <iostream>
#include <string>
#include <vector>
class SharedPointer {
public:
SharedPointer()
:ref_count(0)
{
}
int ref_count;
};
class Handler {
public:
SharedPointer *shared_pointer;
std::string name;
Handler(std::string name)
:shared_pointer(NULL),
name(name)
{
std::cout << "Constructing " << name << std::endl;
}
~Handler(){
std::cout << "Destructing " << name << std::endl;
// Emitter is still alive
if(shared_pointer && shared_pointer->ref_count){
shared_pointer->ref_count--;
if(!shared_pointer->ref_count){
delete shared_pointer;
std::cout << "- - Emitter is dead, so deleting shared ptr " << std::endl;
}
else {
std::cout << "- - Emitter is still alive, so leaving shared ptr " << std::endl;
}
}
}
void Run(){std::cout<<"Running"<<std::endl;}
};
class SmartHandler {
public:
Handler *handler;
SharedPointer *shared_pointer;
SmartHandler(Handler *handler, SharedPointer *shared_pointer)
:handler(handler),
shared_pointer(shared_pointer)
{
handler->shared_pointer = shared_pointer;
handler->shared_pointer->ref_count++;
}
};
class Emitter {
public:
std::vector<SmartHandler> handlers;
~Emitter(){
for(size_t i = 0; i < handlers.size(); i++){
std::cout << "Removing a handler" << std::endl;
if(handlers[i].shared_pointer && handlers[i].shared_pointer->ref_count){
handlers[i].shared_pointer->ref_count--;
if(!handlers[i].shared_pointer->ref_count){
delete handlers[i].shared_pointer;
std::cout << "- - Handler is dead, so deleting shared ptr " << std::endl;
}
else {
std::cout << "- - " << handlers[i].handler->name << " is still alive, so leaving shared ptr " << std::endl;
}
}
}
}
void Attach(Handler *handler){
SharedPointer *shared_pointer = new SharedPointer();
shared_pointer->ref_count++;
SmartHandler smart_handler(handler, shared_pointer);
handlers.push_back(smart_handler);
}
void Detach(Handler *handler){
// find the handler, remove
}
void Emit(){
for(size_t i = 0; i < handlers.size(); i++){
if(handlers[i].handler && handlers[i].shared_pointer->ref_count > 1){
std::cout << "Calling Run() for handler " << handlers[i].handler->name << std::endl;
handlers[i].handler->Run();
}
else{
std::cout << "This handler appears to be dead" << std::endl;
}
}
}
};
int main()
{
Handler h_scope_1("h_scope_1");
{
Emitter emitter;
emitter.Attach(&h_scope_1);
Handler h_scope_2("h_scope_2");
emitter.Attach(&h_scope_2);
{
Handler h_scope_3("h_scope_3");
emitter.Attach(&h_scope_3);
}
emitter.Emit();
}
}输出
Constructing h_scope_1
Constructing h_scope_2
Constructing h_scope_3
Destructing h_scope_3
- - Emitter is still alive, so leaving shared ptr
Calling Run() for handler h_scope_1
Running
Calling Run() for handler h_scope_2
Running
This handler appears to be dead
Destructing h_scope_2
- - Emitter is still alive, so leaving shared ptr
Removing a handler
- - h_scope_1 is still alive, so leaving shared ptr
Removing a handler
- - Handler is dead, so deleting shared ptr
Removing a handler
- - Handler is dead, so deleting shared ptr
Destructing h_scope_1
- - Emitter is dead, so deleting shared ptr https://stackoverflow.com/questions/63406345
复制相似问题