c++如何判断二进制相同的对象?

265 天前
 LuckyPocketWatch

假如有两个自定义类 class A 和 class B ,这两个自定义类的对象长度均为 32 字节,然后有如下代码

A* ptr = new A(/*paratemerA*/);  //先生成一个 class A 的对象为 objectA
A* objectA = ptr;

if(/*condition == true*/){
    ptr->~A();  //销毁对象 class A ,但内存没有还给系统
    ptr = new B(/*paratemerB*/);//在原来的内存上生成一个 class B 的对象为 objectB
}

if(ptr == objectA)
    ptr->doSomething();

objectA 和 objectB 这两个类对象,长度均为 32 字节,这两个对象创建在相同的内存里(创建时间不一样),然后这段代码在运行时出现了一个巧合,生成的这两个对象二进制完全一样

那这种情况下 C++时如何判断 ptr == objectA 这段代码的?

2750 次点击
所在节点    C++
36 条回复
codehz
265 天前
需要考虑的问题是为什么你会有一个无效的指针需要比较?有这个无效的指针在,你问题是解决不完的…
sunstar
265 天前
ABA 问题?可以看看 brpc 的对象池
polaa
265 天前
感觉你可能需要看 malloc 或者 calloc 相关堆实现
包括 free chunk 之后插入 fast bin 或者 tcache 之类的
好像涉及 uaf 或者 undefined behavior 漏洞吧
堆相关知识忘光了 就这些吧
Inn0Vat10n
265 天前
c++这里比的就是指针里存的地址,实际指向什么,指向的东西是不是合法的是不管的
ashong
265 天前
调用了析构而没有删除,但新的 ptr 应该是指向新的 B 对象
xiadong1994
265 天前
你是可以要求编译器在指定的内存地址里面 new object 的,所以这不一定是巧合。https://isocpp.org/wiki/faq/dtors#placement-new

ptr 能放 B 对象的指针说明这是一个父类指针指向子类的情况?那么比较 A*和 B*地址的时候应该会隐式转换成父类指针再比较。同类型指针指向同样地地址就是相同的。
ryd994
265 天前
你这个情况不正常。既然 A 的内存没有还给系统,那下面的 new 分配内存的时候就不会分配到 A 的内存。否则内存管理就有 bug 了。libc 这么多年,你随便就遇到内存管理 bug 的概率基本可以忽略。

最简单的办法就是全局内存日志。在构造和析构函数里打日志用来分析

一般没人乱飞野指针的。一般是配合引用计数或者 autoptr/smartptr 之类的使用。
那引用计数也可以打日志
ryd994
265 天前
如果你只是想区分 A 对象和 B 对象,那让对象储存自己的名字即可,在构造函数里写入这个名字
lany
265 天前
objectA 指针里面存的 class A 的起始地址
geelaw
265 天前
假设你的代码是

A *ptr = new A();
A *objectA = ptr;
ptr->~A();
ptr = new (ptr) B(); // 注意这里需要用 placement new
if (ptr == objectA) ptr->doSomething();

并且 B 是 A 的派生类,并且假设 struct B : A { /* 没有额外的成员 */ };

第一,我不知道 new (ptr) B() 是否是未定义行为,这需要翻阅标准。(适合于 A 的 storage 一定适合于 B 吗?)

第二,接下来比较 ptr 和 objectA 绝对是 undefined behavior ,因为 objectA 最后一次赋值的时候指向的对象已经不存在了,所以 objectA 不是有效的指针——这件事情和原来的 storage 上面现在有没有 B 类型的对象、B 是不是 A 的子类没有任何关系。

让我来写一个正确的版本:

char alignas(B) storage[sizeof(B)];
A *ptr = new (storage) A();
A *objectA = ptr;

ptr->~A();
ptr = new (ptr) B();

objectA = std::launder(objectA); // 这一步非常重要

if (objectA == ptr) ptr->doSomething(); /* if 的 true 分支会运行 */
geelaw
265 天前
@geelaw #10 原来的问题:C++ 如何判断 ptr == objectA 这段代码的?

既然是未定义行为,编译器可以选择格式化你的硬盘,但大多数编译器并不会这样做。
在我转写的第一段代码里,比较可能发生的有两种:

1. 无事发生,直接进行数值的比较,因此 true 分支会运行。
2. 编译器意识到
(i) ptr 赋值获得的是新对象
(ii) objectA 在 ptr 赋值之后就没有再赋值过
于是意识到 objectA 和 ptr 在标准看来不可能同时有效地指向同一个对象,因此直接删除 if 的 true 分支,导致 true 分支不执行。
dangyuluo
265 天前
```
ptr->~A(); //销毁对象 class A ,但内存没有还给系统
ptr = new B(/*paratemerB*/);//在原来的内存上生成一个 class B 的对象为 objectB
```
并不能保证在原来的内存上生成一个 class B ,除非你用了 placement new

而且这是个 UB
dangyuluo
265 天前
@gleelaw `operator==`在两个同类型指针上应该是 well defined 。`*ptr`才是 UB 。

https://godbolt.org/z/7Kzs4x4Mn
iceheart
265 天前
就是地址比较,地址肯定不同,所以 if 条件肯定不成立
lopssh
265 天前
你这代码会在编译时就被咔擦掉吧。。。
你可以将 A*的变量赋值为 B*,你这 A/B 是相互不兼容的吧?那不是动态类型语言的活儿么。
lopssh
265 天前
@sunstar ABA 是先 A 然后 B ,然后再 A ,丢失了有关于 B 的信息,这个例子就只是 AA 。
lopssh
265 天前
A* ptr = new A(/*paratemerA*/); //先生成一个 class A 的对象为 objectA
A* objectA = ptr;

if(/*condition == true*/){
ptr->~A(); //销毁对象 class A ,但内存没有还给系统
}

if(ptr == objectA)
ptr->doSomething();

我看你还是用这个来举例吧。
那句 ptr 的赋值毫不影响程序逻辑,如果 B 是 A 的子类的话,
blinue
265 天前
你对指针有很大误解,学好基础啊
hankai17
265 天前
感觉是设计不合理 出现内存池条件竞争
可以看一下 brpc 内存池管理
mingl0280
265 天前
你不会觉得 ptr = new B 能编译过吧?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/965933

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX