C++ C++;成员函数能够访问数据,即使它删除了调用它的对象

C++ C++;成员函数能够访问数据,即使它删除了调用它的对象,c++,return,member,delete-operator,C++,Return,Member,Delete Operator,下面是我遇到的一个场景:- #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{

下面是我遇到的一个场景:-

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

}
删除OnState后执行?id:-0


注意。

您只能删除指针,不能删除引用。
看看这个。这可能会对您有所帮助。

您只能删除指针,不能删除引用。 看看这个。这可能会对您有所帮助。

问题1“为什么仍然可以访问已删除实例的虚拟函数和成员变量”

在以下场景中,函数调用在调用虚拟函数和成员变量时使用实例:删除后,如果在释放的块中意外分配了另一个分配,则在删除的实例中更改虚拟函数指针的值,这将在调用时触发异常

内存删除只会导致堆管理将堆块返回到堆的空闲列表中。(适用于glibc和windows堆)。堆永远不会将虚拟页返回虚拟内存管理器,这意味着可以访问堆中已删除的内存,并且只有在有效范围内读取时不会触发任何异常

问题2“我认为函数定义并没有存储在特定于实例的内存中,但这并不能解释“id”值如何仍然可以访问。”

可执行文件中的函数定义位于代码段中(因为dll将在进程之间共享,在某些情况下会触发COW),新的变量将在堆中分配。如前所述,内存是可以访问的,因此在堆块被其他分配占用之前,您仍然可以访问以前的值(因为我知道windows heap和glic都不会因为性能原因重新填充或重置删除块的值)。

问题1“为什么仍然可以访问已删除实例的虚拟函数和成员变量?”

在以下场景中,函数调用在调用虚拟函数和成员变量时使用实例:删除后,如果在释放的块中意外分配了另一个分配,则在删除的实例中更改虚拟函数指针的值,这将在调用时触发异常

内存删除只会导致堆管理将堆块返回到堆的空闲列表中。(适用于glibc和windows堆)。堆永远不会将虚拟页返回虚拟内存管理器,这意味着可以访问堆中已删除的内存,并且只有在有效范围内读取时不会触发任何异常

问题2“我认为函数定义并没有存储在特定于实例的内存中,但这并不能解释“id”值如何仍然可以访问。”


可执行文件中的函数定义位于代码段中(因为dll将在进程之间共享,在某些情况下会触发COW),新的变量将在堆中分配。如前所述,内存是可以访问的,因此在堆块被其他分配占用之前,您仍然可以访问以前的值(因为我知道windows heap和glic都不会因为性能原因重新填充或重置删除块的值)。

访问已删除对象的成员会导致未定义的行为

读取已删除对象的成员值通常会返回该地址中存在的任何内容。请记住,在此期间可以在该地址分配新对象,因此可以从旧成员值中获得不同的值

您正在使用
new
操作符分配
OnState
对象,因此它将被分配到堆上。成员变量是存储在堆内存中的对象的一部分,您有一个指向它的指针。即使删除了对象,也可以通过指针读取其成员


只要未回收虚拟内存页,读取访问就不应引发异常(无论如何,依赖此假设是个坏主意)。

访问已删除对象的成员会导致未定义的行为

读取已删除对象的成员值通常会返回该地址中存在的任何内容。请记住,在此期间可以在该地址分配新对象,因此可以从旧成员值中获得不同的值

您正在使用
new
操作符分配
OnState
对象,因此它将被分配到堆上。成员变量是存储在堆内存中的对象的一部分,您有一个指向它的指针。即使删除了对象,也可以通过指针读取其成员


只要虚拟内存页未被回收,读取访问就不应引发异常(无论如何,依赖此假设是个坏主意)。

代理在任何地方都没有定义。请将一个saw发布到迟到:)抱歉,现在添加了它。(粘贴出错)您的程序通过在对象生命周期结束后访问对象的方式显示未定义的行为。“似乎有效”是未定义行为的一种可能表现形式。好吧,如果函数根本没有使用id呢。如果在changeState()之后,该方法中只有一个return语句会怎么样。这是一个安全的功能吗?(它现在显然不安全,因为它正在打印“id”)
Agent
在任何地方都没有定义。请将一个saw发布到迟到:)抱歉,现在添加了它。(粘贴出错)您的程序通过在对象生命周期结束后访问对象的方式显示未定义的行为。“似乎有效”是未定义行为的一种可能表现形式。好吧,如果函数根本没有使用id呢。如果在changeState()之后,该方法中只有一个return语句会怎么样。这是一个安全的功能吗?(现在打印“id”时显然不安全)
agent updating. will execute current State 
OnState executing
removing OnState id :- 0
removing State