即使删除了调用它的对象,也能访问数据的c++成员函数
C++ Member function able to access data even it deleted the object that called it
这是我遇到的一个场景:-
#include <iostream>
class Agent;
class State;
class OffState;
class OnState;
class State
{
public:
virtual void execute(Agent * agent) = 0;
virtual ~State() {std::cout << "removing Staten";}
};
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();
}
在这里,Agent的当前状态被初始化为一个OnState对象。该对象通过Agent中的update()方法访问。调用OnState的execute方法。现在这个execute方法间接地删除调用它的OnState对象。然而,在此之后,控制权被传递回OnState对象中的execute()方法。更重要的是,它能够打印"id"的值。内存指针不应该因为delete currentState而被删除吗?
或者在某些情况下,系统可能会崩溃,并且在某些情况下,内存内容不会立即被操作系统填充。
我认为函数定义不是存储在特定于实例的内存中,但这并不能解释"id"值如何仍然可以访问。
代码的输出是:-
agent updating. will execute current State
OnState executing
removing OnState id :- 0
removing State
删除OnState后执行?id: - 0
问候。
只能删除指针,不能删除引用。点击这个链接。
问题1 "为什么仍然可以访问已删除实例的虚函数和成员变量"
函数调用使用实例时调用虚函数和成员变量,在以下场景:在你删除后,如果另一个分配碰巧在你释放的块中分配,并且改变了你删除实例中的虚函数指针的值,这将在你调用时触发异常
内存删除只会导致堆块被堆管理返回到空闲堆列表中。(适用于glibc和Windows heap)。堆永远不会将虚拟页面返回给虚拟内存管理器,这意味着在堆中删除的内存可以访问,并且只在有效范围内读取不会触发任何异常。
问题2 "我认为函数定义不是存储在特定于实例的内存中,但这并不能解释"id"值如何仍然可以访问。"
可执行文件中的函数定义在代码段中(对于dll将在进程之间共享,并且在某些高级文件中会触发COW), new变量分配在堆中。如前所述,可以访问内存,因此在堆块被其他分配占用之前,您仍然可以访问先前的值(据我所知,由于性能原因,windows堆和glic都不会重新填充或重置删除块的值)。
访问已删除对象的成员将导致未定义行为
读取已删除对象的成员值通常会返回该地址的值。请记住,在此期间可以在该地址分配新对象,因此您可以获得与旧成员值不同的值。
您使用new
操作符来分配OnState
对象,因此它将在堆上分配。成员变量是存储在堆内存中的对象的一部分,您有指向它的指针。即使删除了对象,仍然可以通过指针读取其成员。
只要不回收虚拟内存页,读访问就不应该抛出异常(无论如何,依赖这个假设是一个坏主意)。
- 在类 A 中创建类型为 B 类的向量 - 访问数据 [C++] [成员在两个类中都是私有的]
- C++ 11 中的锁定是否保证访问数据的新鲜度?
- 访问数据成员(本身是对象)的数据成员,就好像它们是类成员一样
- 读取大文件(>2GB)(文本文件包含以太网数据)并通过不同参数随机访问数据的最佳方法是什么?
- 向量下标出的范围错误.即使向量的索引大于访问数据的索引,也会发生误差
- 通过指针访问数据(重新解释转换)与 .或 ->运算符
- C Koala图库 - 了解访问数据结构的语法
- CAFFE C - 其他层中的访问数据
- C++ 访问数据的链表实现
- 基于两个程序之间的事件触发器访问数据(内存)
- 引用本地可访问数据的正当理由
- 函数调用不起作用,矢量访问数据
- BMP 文件,访问数据
- 如何从其他类访问数据私有内部类
- 如何从双精度向量的向量访问数据
- 从 Vector3f 访问数据
- 从文件访问数据
- 如何在进程已经在访问数据结构时修改数据结构
- 如何从 GMemoryOutputStream 访问数据
- 使用 ostream 从另一个类的结构访问数据