2016-09-01 6 views
2

Вот сценарий, я наткнулся на: -функция C++ член в состоянии получить доступ к данным даже удалил объект, который назвал его

#include <iostream> 

class Agent; 
class State; 
class OffState; 
class OnState; 

class State 
{ 
public: 
    virtual void execute(Agent * agent) = 0; 
    virtual ~State() {std::cout << "removing State\n";} 
}; 

class Agent{ 

    State * currentState ; 
public: 

    Agent(); 
    void update(){ 
     std::cout << "agent updating. will execute current State " << std::endl; 
     currentState->execute(this); 
    } 

    void changeState(State * newState){ 
     delete currentState; 
     currentState = newState; 
    } 

}; 

class OffState : public State 
{ 
public: 
~OffState() {std::cout << "deleting OffState Object" <<std::endl;} 
    void execute(Agent * agent){ 
     std::cout << "Nothing happens in the off State " << std::endl; 
    } 
}; 


class OnState : public State 
{ 
static int count ; 
int id; 
public: 
    OnState(){ 
     id = count; 
     count++; 
    } 

    ~OnState() {std::cout << "removing OnState id :- " <id<<std::endl;} 

     void execute(Agent * agent){ 
      std::cout << "OnState executing" << std::endl; 
      agent->changeState(new OffState()); 
      std::cout << "executed after deleting OnState ? id:- " << id << std::endl; 
     } 
}; 
int OnState::count = 0; 

Agent::Agent():currentState(new OnState()){ 
} 


main(){ 

    Agent smith; 
    smith.update(); 

} 

В этом текущее состояние Агента инициализируется к О государственных объектов. Доступ к этому объекту осуществляется с помощью метода update() в Agent. Это вызывает метод выполнения OnState. Теперь этот метод execute косвенно удаляет объект OnState, который его вызвал. Однако после этого управление возвращается к методу execute() в объекте OnState. Более того, он может печатать значение «id». Не следует удалять память из-за удаления currentState.

Или это случай, когда в некоторых случаях система может произойти сбой, а в некоторых случаях содержимое памяти не будет немедленно заполнено операционной системой.

Я думал, что определение функции не сохраняется в памяти, специфичной для экземпляров как таковых, но это не объясняет, как значение «id» все еще доступно.

Выходной код был: -

agent updating. will execute current State 
OnState executing 
removing OnState id :- 0 
removing State 

выполняется после удаления О государственных? id: - 0

С уважением.

+0

«Агент» не определен нигде. Пожалуйста, опубликуйте [MCVE] (http://stackoverflow.com/help/mcve) –

+0

видел его до конца :) – Roby

+0

извините, добавлено сейчас. (паста пошла не так) – ameyask86

ответ

0

Вы можете удалить указатели, а не ссылки. Проверьте это link. Это может вам помочь.

0

Вопрос 1 «почему все еще может получить доступ к удаленному экземпляра виртуальных функций и переменному-член»

Функции использование вызова экземпляр при вызове виртуальных функций и переменных-членов, в следующем сценарии: После вашего удаления, если другое распределение между прочим выделяется в вашем выпущенном блоке и изменить значения указателя виртуальной функции в удаленном экземпляре, что вызовет исключение при вызове.

Удаление памяти приводит к тому, что куча кучи возвращается обратно в свободный список кучи посредством управления кучей (как для glibc, так и для кучи окон). Куча никогда не возвращает виртуальные страницы обратно в виртуальный менеджер memeory, что означает, что удаленная память в куче вы можете получить, и когда только чтение в допустимом диапазоне не вызовет каких-либо исключений.

Вопрос 2 «Я думал, что определение функции не сохраняется в памяти, специфичной для экземпляров как таковых, но это не объясняет, как значение« id »все еще доступно».

Определение функции в вашем исполняемом файле находится в сегменте кода (для dll, который был бы разделен между процессами, а в некоторых senrior - COW), новые переменные выделяются в кучу. Как объяснено, к памяти можно получить доступ, так что до того, как блок кучи будет занят другим распределением, вы все равно сможете получить доступ к своему предыдущему значению (поскольку я знаю, что куча и glic окна не будут пополнять или сбросить значение блока удаления из-за производительности).

0

Доступ к элементу удаленного объекта приводит к undefined поведение.

Чтение значения элемента удаленного объекта обычно возвращает все, что присутствует на этом адресе. Имейте в виду, что новый объект может быть выделен на этом адресе тем временем, поэтому вы можете получить другое значение от старого значения элемента.

Вы используете оператор new для размещения объекта OnState, поэтому он будет выделен на кучу. Переменная-член является частью объекта, хранящегося в кучевой памяти, и у вас есть указатель на него. Даже если вы удалили объект, вы все равно можете прочитать его элементы через указатель.

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