指针可以安全地和可移植地用作对象ID吗?

时间:2011-06-20 09:20:46

标签: c++ pointers

假设我有一堆有关类A实例的有效指针。我能安全且可移植地假设指针在整个对象生命周期内保持不变吗?换句话说,我可以使用指向对象的指针作为唯一对象ID吗?

9 个答案:

答案 0 :(得分:8)

不确定;我不明白为什么不。

内存地址几乎就是对象标识的定义(暂时取出等式)。

答案 1 :(得分:5)

不一定 - 这取决于您如何分配这些实例以及随后对它们执行的操作。例如,假设您创建了一个对象数组,然后重新分配该数组。现在无法保证对象仍然位于同一位置。

答案 2 :(得分:4)

如果您确定在删除对象后不会创建任何对象,则只能执行此操作。可以在先前删除的对象的同一地址创建新对象,这可能是一个问题:您不希望两个不同的对象具有相同的ID。

答案 3 :(得分:4)

虽然通常情况下内存地址唯一地标识对象。有两个重要的警告:

  1. 删除对象时,可以重复使用该地址(很可能是同一类的对象)。

  2. 如果您正在处理不同的进程,则两个进程中的地址可能相同。

答案 4 :(得分:2)

只要对象停留在内存中并且您总是引用同一个实例(例如,您没有按值传递它,然后将该对象与原始或另一个缓存副本进行比较),该地址将始终保持不变,指针是一个合理的ID。这显然是正确的 - 如果对象在内存中移动,指针将不再起作用,并且标准保证指向不同对象的指针与不同的值进行比较。 [这就是为什么你不能有零长度的对象,所以内存中的下面的对象有不同的地址。]

但是,如果对象将通过网络传递或保存到磁盘,显然这将不再起作用,并且您必须逐个元素地比较对象,或者让它包含唯一的id值(又名主键)。

ETA:可怕的是,如果重新分配包含对象的内存,则值会有所不同,但显然指针根本不会有效,因此无论您希望指针是唯一的,您的程序都将被破坏或不。 (相反,如果你使用智能点来跟踪repllocs - 本质上是C#和.NET如何工作 - 值不一定相同,但指针的值在对象的不同实例之间仍然会有所不同。)事实上,这是规则 - 只要指针有效,你应该能够比较它们,但是你不能缓存它并期望它在以后的某个未确定的时间仍然工作(如果你先破坏对象),所以如果你确定你不会,那没关系,但要记住,通常你会想要在某个时候串行化对象,然后从一开始就设计好它们会更好。

答案 5 :(得分:2)

一个担心(这是一个真正的担心)是布谷鸟指针。

假设您缓存指针值A。

然后释放该指针,然后再分配一个新对象B.

内存分配器可以选择用于A的位置来分配B.

表格代码: if(new_pointer!= old_pointer){...}

可能没有意识到对象已经改变。

http://www.nobugs.org/blog/archives/2004/11/20/cuckoo-pointers/

编辑:

另外一种方法是,你的对象在活着时总是在同一个地址,但该地址的对象并不总是你想要的对象。

答案 6 :(得分:1)

如果指向不同子类的指针不是c-cast为void *,那么是的,比较指针检查它是否是同一个对象没问题。

在将地址存储为void *或uint值以用于ID目的的情况下,当一个类从多个类继承时会出现一些不那么明显的问题。

考虑从类A和类B继承的类C.如果通过类A指针引用类C,它将显示等于通过类B指针引用同一对象。

C* c = new C();
A* a = C;
B* b = C;
a == b; // true

但是,如果从类A指针转换为C指针指向void指针,则可能最终得到子对象地址,而不是完整对象的地址。这些类型将在正常情况下跟踪这一情况,并且只在使用void指针时才会担心。

void* avoid = (void*)a;
void* bvoid = (void*)b;
avoid == bvoid; // false

要保证最派生和完整对象的正确地址,请使用dynamic_cast(myObject)。但请记住,它必须是一个多态类,并且必须启用RTTI才能使dynamic_cast工作。

答案 7 :(得分:0)

回过头来,有人说多态性涉及为一个对象提供多个地址?

我很确定,这就是虚函数表的用途。在调用Object1->func1()之前,Object1的类型和地址用作vtable的键,并获取func1()的地址。对?进行重铸,比如回到基类,如:

BaseClass* OPtr = reinterpret_cast<BaseClass*>(DerivedObjectPtr);
OPtr->func1();

会使密钥对address + type不同,因此可以返回不同的函数指针。

无论如何,这就是我编写运行时内容的方法。不知道多重继承,这是一个令人厌恶的imo。我也将对象地址用作ID s。我真的找不到它的任何错误,其他人可以吗?

答案 8 :(得分:-2)

如果A类的所有实例都存储在堆中,是的,它们将在整个程序生命周期内保持不变。相反,如果在堆栈中创建实例,那么绝对不会,因为在范围的末尾它们会被销毁。