在这种情况下我应该在哪里调用删除?

时间:2017-02-09 16:01:30

标签: c++ pointers delete-operator

我正在使用从此处获取的状态模式编写有限状态机:

State Pattern

我在这里实现了它:

My Machine Github

回想一下我的想象,你有这种情况:

//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) );

        }
    }

};

使用setStatePtr(new OFFState(&machine))

初始化机器

我的问题在这里提出:因为我正在使用new运算符,所以我应该在某处调用delete但是在哪里?我尝试在setStatePtr函数中执行:

void setStatePtr(.. s){
    delete _state;
    _state = s;
}

但它不起作用。

我没有定义任何指针p * = new p();所以我不知道在哪里删除任何删除。我的问题更具有道德性,所以请不要建议其他实施或使用,因为我仍会有同样的疑问:)

当我做foo(新事物)时,我在哪里打电话给删除?

提前感谢,

安德烈

3 个答案:

答案 0 :(得分:2)

旧方法是以这种方式实现该方法:

void setStatePtr(AbstrState *state){
   if( _state != state ) {
       delete _state;
       _state = state;
   }
}

但正确的方法是使用智能指针:

class machine{
public:

    void setStatePtr( std::unique_ptr<AbstrState> state){

        _state = std::move( state );
    }

private:
    std::unique_ptr<AbstrState> _state;
};
这样你就有两个好处:

  • 自动管理资源并在必要时销毁
  • 您的方法签名清楚地表明它将取得传递对象的所有权,当您传递原始指针时,它不清楚,您必须在文档中解释,这容易出错

答案 1 :(得分:0)

你的错误是成员setStatePtr()。指针来自哪里?它所引用的对象什么时候被删除?我们只是不知道。

这就是为什么C ++现在拥有您拥有的对象的唯一指针,以及多个实体引用的对象的共享指针。你刚才提到的指针很简单。通常,类似于州的东西会被深层复制。该集接受一个const引用,并分配给一个不是指针而是完整对象的成员。

除了实现像STL本身这样的低级结构外,

new和delete在C ++中不再使用了很多。

答案 2 :(得分:-1)

谁调用new,谁调用delete。 通常,函数foo可能不会调用delete,因为无法判断指针是否由new分配(除非以这种方式明确指定foo的使用)。

但如果你使用RAII习语,那将是另一个故事。这似乎就是这种情况。然后你的班级应该在复制分配,销毁或任何其他应该“免费”的操作中调用delete。较旧的资源。

顺便说一句,以下划线(_)开头的名称保留给实现,因此你不应该使用它。