c++ - C ++:指向对象的未分配指针可以反复安全地取消引用......为什么?
问题描述
为什么这段代码实际上可靠地工作,不是不稳定的,未定义的?它取消引用未分配的、悬空的指向对象的指针。谢谢。
#include <iostream>
using namespace std;
class Base{
public:
void vf()
{
cout<<"vf\n";
}
void pr(){
cout<<"vb\n";
}
};
int main() {
Base* b ;
//Base * bp = new Base; //trying to disrupt memory
char ar[]= "ttttttttttt"; //trying to disrupt memory
b->pr();
char aa[]= "ttttttttttt";
b->vf();
return 0;
}
解决方案
欢迎来到未定义行为的奇妙世界!根据 C++ 规范,此问题的行为是未定义的,因此您所看到的可能在您的系统上工作但在其他系统上崩溃,反之亦然。
实际上,这里发生的事情可能是编译器如何为成员函数生成代码的产物。通常,成员函数如下所示:
void doSomething() {
cout << "Hello!" << endl;
}
可能会被编译为像这样的自由函数:
void Base_doSomething(Base* this) {
cout << "Hello!" << endl;
}
从这个意义上说,当你写
bf->doSomething();
编译器将其视为您已编写
Base_doSomething(bf);
并且没有任何不好的事情发生,因为Base_doSomething
没有引用this
指针,这是所有坏事发生的地方。
现在,这是非常脆弱的。如果您尝试读取该Base
类型的任何数据成员,则此代码将崩溃,因为您正在从错误的指针中读取。类似地,如果doSomething
是一个virtual
函数,你会遇到崩溃,因为调用一个虚函数(通常)需要从接收者对象中读取以找到vtable以确定要调用哪个函数,然后一个悬空指针将导致错误的内存访问.
所以,总结一下:
- 此代码会导致未定义的行为,因此不能保证您看到的特定行为会发生或跨平台工作。
- 尽管在语法上
bp->doSomething()
看起来像指针解引用,但它实际上可能不涉及指针解引用。 - 成员函数通常编译为具有
this
作为第一个参数传递的“隐式”指针的自由函数。 - 虚函数的工作方式与此不同,因此您希望在那里看到不同的行为。
希望这可以帮助!
推荐阅读
- python - 如何比较烧瓶中的两个密码
- tensorflow - Google Colab:TPU 不支持的数据类型:double,由输出 cond_8/Merge:0 引起
- ruby - 从字符串中删除空格,然后转换为整数
- git - 有什么方法可以将本地 git-p4 存储库连接到远程 git 存储库,同时保持与 p4 仓库的连接?
- google-vision - 使用没有文件扩展名的图像将训练数据导入 CloudML
- c# - 空游戏对象未停用
- spring - 保护刚刚暴露端点的 Spring Boot
- python - 如何仅使用 GridSearchCV 进行简单的交叉验证
- javascript - 使用节点创建服务器时出现问题,出现“TypeError: Cannot read property 'db' of null”
- sql - What is the correct way of inserting values in to tables and link tables in oracle?