2017-02-09 2 views
0

Я программирование конечного автомата с использованием государственного образца взята отсюда:Где я должен позвонить delete в этом случае?

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

     } 
    } 

}; 

Станок является инициативой ialized with setStatePtr(new OFFState(&machine))

Этот вопрос возникает здесь: поскольку я использую новый оператор, я должен вызвать delete где-нибудь, а где? Я попытался выполнить функцию setStatePtr:

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

но это не сработает.

Я не определяю никакого указателя p * = new p(); поэтому я не знаю, где можно вызвать любое удаление. Мой вопрос более точный, поэтому, пожалуйста, не предлагайте другую реализацию или обычаи, потому что у меня все еще будут те же сомнения :)

Когда я делаю foo (что-то новое), где я могу назвать delete?

Спасибо заранее,

Andrea

+7

Используйте умные указатели. 'std :: shared_ptr' приходит на ум. –

+0

@ Cheersandhth.-Alf - вот ответ. Может быть, опубликовать его как один? – hoodaticus

+0

'std :: unique_ptr' вызовет удаление в нужном месте. –

ответ

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; 
}; 

таким образом, у вас есть 2 преимущества:

  • ресурс управляется автоматически и уничтожается при необходимости
  • ваш подпись метода ясно показывает, что он будет владеть переданным объектом, когда вы передаете необработанный указатель, это неясно, и вы должны объяснить, что в документации, которая подвержена ошибкам
+0

Большое спасибо, я попробую это. Имеет ли unique_ptr тот же синтаксис, чтобы получить доступ к указанному значению так же, как в cpp? Moerover, в этом случае, я должен вызвать setStatePtr, как в моем примере, просто выполнив: setStatePtr (новый ONState (_context)); –

+0

@ AndreaNisticт да использование того же 'ptr-> foobar()' и т. Д. Если у вас есть C++ 14 или более поздняя версия, вы должны использовать 'std :: make_unique', иначе' std :: unique_ptr (новый OnState (_context)) ', но я бы создал typedef для этого указателя – Slava

+0

Большое спасибо, да, я сделал typedef для этого.Очень последний вопрос о теме: если мне нужна функция, возвращающая этот указатель (getter), как мне это сделать? –

-1

Кто называет новый, который называет удалить. Как правило, функция foo не может вызывать удаление, потому что невозможно определить, назначен ли указатель новым или нет (если явно не указано использование foo).

Но если вы используете идиому RAII, это будет другая история. Кажется, это так. Затем ваш класс должен вызывать удаление во время копирования, уничтожения или любой другой операции, которая должна «освобождать» старый ресурс.

Кстати, имена, начинающиеся с подчеркивания (_), зарезервированы для реализации, и поэтому вы не должны его использовать.

+2

Не совсем верно об именах с подчеркиванием, это либо подчеркивание, и заглавная буква, либо двойное подчеркивание, OP is fine – Slava

+1

Каждое имя, которое начинается с подчеркивание зарезервировано для реализации для использования в качестве имени в глобальном пространстве имен. [link] (http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) ​​ – felix

+0

это неверно. Какие-нибудь основания для этого? – Slava

0

Ваша ошибка в членстве setStatePtr() , Откуда этот указатель? Когда объект, на который он ссылается, удаляется? Мы просто не знаем.

Вот почему C++ теперь имеет уникальный указатель, s для ваших объектов и общие указатели для объектов, на которые ссылаются несколько объектов. Указатели, на которые вы просто ссылаетесь, равны. Обычно что-то вроде государства принимается глубокой копией. Набор принимает ссылку на const, и вы назначаете элемент, который не является указателем, а полным объектом.

новые и удаленные больше не используются в C++, за исключением реализации низкоуровневых структур, таких как STL.

Смежные вопросы