Where should I call delete in this case?
本问题已经有最佳答案,请猛点这里访问。
我正在使用从这里获取的状态模式对有限状态机进行编程:
状态模式
我已经在这里实现了它:
我的机器Github
回想一下我曾经想象过的情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | //MAIN MACHINE class machine{ public: void handle(){ _state->handle(); } void setStatePtr(AbstrState *state){ _state = state; } private: AbstrState* _state; }; //BASE STATE class AbstrState { public: AbstrState(machine* m){ _context = m; } virtual void handle() = 0; protected: machine *_context; }; //ACTUAL STATES class ONState : AbstrState{ public: ONState(machine *m) : AbstrState(m) {} void handle(){ if(BUTTON_PRESSED){ _context->setStatePtr( new OFFState(_context)); } } }; class OFFState : AbstrState{ public: OFFState(machine *m) : AbstrState(m) {} void handle(){ if(BUTTON_PRESSED){ _context->setStatePtr( new ONState(_context) ); } } }; |
机器是用
我的问题出现在这里:由于我使用了新的运算符,我应该在哪里调用delete?我尝试了setstateptr函数,它执行以下操作:
1 2 3 4 | void setStatePtr(.. s){ delete _state; _state = s; } |
但它不起作用。
我没有定义任何指针p*=new p();所以我不知道在哪里调用任何删除。我的问题更具道德性,因此请不要建议其他实施或惯例,因为我仍然有同样的疑问:)
当我做foo(新事物)时,我在哪里可以调用delete?
提前感谢,
安德莉亚
旧方法是通过以下方式实现该方法:
1 2 3 4 5 6 | void setStatePtr(AbstrState *state){ if( _state != state ) { delete _state; _state = state; } } |
但正确的方法是使用智能指针:
1 2 3 4 5 6 7 8 9 10 11 | class machine{ public: void setStatePtr( std::unique_ptr<AbstrState> state){ _state = std::move( state ); } private: std::unique_ptr<AbstrState> _state; }; |
这样您就有两个好处:
- 资源自动管理,必要时销毁
- 您的方法签名清楚地表明它将获得所传递对象的所有权,当您传递原始指针时,它是不清楚的,并且您必须在文档中解释这一点,这很容易出错。
您的错误是成员setStateDepr()。那个指针是从哪里来的?它所引用的对象何时被删除?我们只是不知道。
这就是为什么C++现在有了独特的指针,对于你拥有的对象,以及对于多个实体引用的对象的共享指针。你刚才提到的指针很简单。通常情况下,类似状态的东西会被深度复制。该集合接受一个常量引用,并将其分配给一个不是指针而是完整对象的成员。
C++中不再使用新的和删除,除了实现像STL本身那样的低级结构。
谁叫新的,谁叫删除。通常情况下,函数foo不能调用delete,因为我们无法判断指针是否由new分配(除非这样明确指定foo的用法)。
但如果你使用的是RAII成语,那就另当别论了。这里似乎是这样。然后您的类应该在副本分配、销毁或任何其他应该"释放"旧资源的操作期间调用delete。
顺便说一下,名称以下划线开头是为实现保留的,因此您不应该使用它。