C++ &引用;“聪明的”;C+中的指针+;98
我有一个C++ &引用;“聪明的”;C+中的指针+;98,c++,C++,我有一个EventEmitter和一个EventHandler对象。将EventHandler*s添加到EventEmitter的处理程序向量中。这使得任何扩展处理程序的对象都可以通过事件发射器通过公共接口调用 现在,当EventHandlers决定在程序员没有意识到的情况下销毁时(通常是复制ctors和=运算符),问题就会出现,EventEmitter最终会调用它,导致程序崩溃 第一个想法是为EventHandler提供对其发射器的引用,以便它可以在销毁期间调用分离函数。但是,现在我们必须考虑
EventEmitter
和一个EventHandler
对象。将EventHandler*
s添加到EventEmitter
的处理程序向量中。这使得任何扩展处理程序的对象都可以通过事件发射器通过公共接口调用
现在,当EventHandler
s决定在程序员没有意识到的情况下销毁时(通常是复制ctors和=运算符),问题就会出现,EventEmitter
最终会调用它,导致程序崩溃
第一个想法是为EventHandler
提供对其发射器的引用,以便它可以在销毁期间调用分离函数。但是,现在我们必须考虑事件发射器决定死亡,然后在任何时候都可以调用处理程序析构函数。我们只是解决了这个问题
这听起来像是一个非常常见的指针问题,我不怀疑它已经在C++11或boost中解决了,但我无法访问这两种语言。是否有一个智能指针系统的通用布局,可以在C++ 98?/p>中解决这个问题?
一些代码来说明
// 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();
}
好的,这就是我想到的。具有引用计数的共享指针。两个对象共享对该指针的访问。当它们死亡时,如果将ref计数降低到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();
}
}
好的,这就是我想到的。具有引用计数的共享指针。两个对象共享对该指针的访问。当它们死亡时,如果将ref计数降低到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();
}
}
<代码> AutoPytTrp/代码>是较弱的GoT代码< UNQuyJOPTR >代码>,这是在旧的C++标准库中的。也许还是自己滚吧。这比表面上看起来更复杂。话虽如此,如果您只是针对您的特定用例而不是一般情况使用它,它应该是好的。这就是我的目标。让它为这两个人工作。那么他们应该怎么做呢?互相指指点点?有某种引用计数系统吗?C++11智能指针使用引用计数。它们甚至是线程安全的(使用atomics)。boost实现仅限于头文件,这些特定模块没有二进制文件。您的编译器或平台是否如此怪异,以至于您无法从他们的C++98 shared_ptr实现中获得灵感或直接使用它?那么,您的实现不工作、代码审查不允许或存在边缘案例缺陷的可能性有多大呢?好主意!我将看看是否可以集成一个。<代码> AutoPPTR <代码>是一个弱的代码,在代码> > UNQuyGyPTR <代码>中,这是在旧的C++标准库中。也许还是自己滚吧。这比表面上看起来更复杂。话虽如此,如果您只是针对您的特定用例而不是一般情况使用它,它应该是好的。这就是我的目标。让它为这两个人工作。那么他们应该怎么做呢?互相指指点点?有某种引用计数系统吗?C++11智能指针使用引用计数。它们甚至是线程安全的(使用atomics)。boost实现仅限于头文件,这些特定模块没有二进制文件。您的编译器或平台是否如此怪异,以至于您无法从他们的C++98 shared_ptr实现中获得灵感或直接使用它?那么,您的实现不工作、代码审查不允许或存在边缘案例缺陷的可能性有多大呢?好主意!我看看能不能集成一个。
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