如何检查两个指针是否指向同一个对象?
考虑两个指针如何检查两个指针是否指向同一个对象?
A* a;
B* b;
A和B是多态的类。 如何检查a和b是否指向同一个对象?
更准确地说,我们指定a和b指向同一个对象,如果存在类型d的一些对象d,使得两个*和* b是d的类层次结构的某个地方。
我建议如下解决方案:
dynamic_cast<void*>(a) == dynamic_cast<void*>(b)
实际上,根据该标准,
dynamic_cast<void*>(v)
产量“的指针最派生对象用V指向(n3242.pdf。 :§5.2.7 - 7)。 如果两者的派生最相同的对象,那么指针指向同一个对象。
我很确定它应该始终从实际的角度正确工作。但理论上,乍看之下,所提出的平等似乎会产生误判,例如,如果b指向A的第一个成员(而不是A的祖先)。虽然A和它的成员实际上不可能获得相同的地址,因为A的虚拟表指针应该位于该成员之前,但该标准并没有强制虚拟表并且没有提及类布局。
所以,我的问题是:
是所提出的解决方案,从标准的角度看是否正确?
有没有关于私人(受保护)继承或cv资格的警告?
有没有更好的解决方案?
[编辑]
我试图提出一些例子示出了相对复杂的场景。在这种情况下,动态交叉转换和静态转换是不明确的。
// proposed impplementation:
template<typename P, typename Q>
bool test_ptrs(const P* p, const Q* q)
{
return (dynamic_cast<const void*>(p) == dynamic_cast<const void*>(q));
}
struct Root
{
virtual ~Root(){};
};
struct A: public Root // nonvirtually
{
};
struct B: public Root // nonvirtually
{
};
struct C: public A, B // nonvirtual diamond started with Root
{
Root another_root_instance;
};
int main()
{
C c;
A* pa= &c;
B* pb= &c;
bool b = (dynamic_cast<void*>(pa) == dynamic_cast<void*>(pb));
Root* pra= dynamic_cast<Root*> (pa);
Root* prb= dynamic_cast<Root*> (pb);
//Root* prc= dynamic_cast<Root*> (&c); // runtime error, ambiguous cast
Root* prr= dynamic_cast<Root*>(pra);
Root* pcar= dynamic_cast<Root*>(pra);
Root* pcbr= dynamic_cast<Root*>(prb);
if(
test_ptrs(pa, pb)
&& test_ptrs(pra, prb)
&& !test_ptrs(pa,&c.another_root_instance)
)
{
printf("\n test passed \n");
}
}
我试图通过比较这些指针指向的地址来解决这个问题。
- 地址它指向基于指针类型的更改。
因此理论上可以说像
a *和b *指向同一个对象,如果存在一些对象C类型C的,使得两个* a和* b是在类某处C.层次结构“
按道理
我们不得不重新审视上述声明像 ” a *和b *指向同一个对象但它obj的ç的内存访问自己的区域C型,使得两个* a和* b是某处C的类层次结构 “”
struct Aa { int a; Aa() {a= 0;} };
struct Bb
{ int b;
Bb() { b= 0;}
};
struct C: Aa, Bb {
};
C c;
Aa *a1 = &c;
Aa *a2 = &c;
Bb *b1 = &c;
Bb *b2 = &c;
cout << &c << "\t"<< &(*a1)<<"\t"<< &(*a2)<<endl;
cout << &c << "\t"<< &(*b1)<<"\t"<< &(*b2)<<endl;
输出:
- &Ç0x0012fd04
- &(* A1)0x0012fd04
- &(* A2)0x0012fd04
- &(* B1)0x0012fd08
- &(* b2)的0x0012fd08
虽然这不能解决您的问题,但我们有一点要在此推断。
这似乎对我来说是最臭的方式来处理,这是引入一个基类对于A & B:
#include <iostream>
struct Base
{
virtual ~Base() {};
};
struct A : public virtual Base
{
int a;
virtual ~A() {};
virtual void afunc() {};
};
struct B : public virtual Base
{
int b;
virtual ~B() {};
virtual void bfunc() {};
};
struct C: A, B
{};
int main()
{
C c;
A *a = &c;
B *b = &c;
std::cout << "a* == " << &(*a) << std::endl;
std::cout << "b* == " << &(*b) << std::endl;
std::cout << "a == b == " << ((void*)a == (void*)b) << std::endl;
Base* ba = a;
Base* bb = b;
std::cout << "ba* == " << &(*ba) << std::endl;
std::cout << "bb* == " << &(*bb) << std::endl;
std::cout << "ba == bb == " << (ba == bb) << std::endl;
return 0;
}
我同意它是最不臭的,虽然,严格来说,它不是一个答案:)。 – user396672 2012-04-02 17:25:53
由于与dynamic_cast
您还可以在类型层次投“杯酒人生”,我建议:
(b != nullptr? dynamic_cast<B*>(a) == b : a == nullptr)
如果a
点,在*b
开始一些子对象,然后dynamic_cast<B*>(a)
必然会返回一个空指针(因为有没有办法B
包含自身)。因此,如果b不是空指针,则dynamic_cast<B*>(a) == b
只有在共享相同的大多数派生类时才会成功。 b是一个空指针的情况下,必须特别处理,因为如果a
不为空,但没有指向从B
派生的类,则dynamic_cast
测试将失败。
但也有涉及多重继承哪里该解决方案将提供一个假阴性(不像你的解决方案,它从来没有给假阴性,但可产生假阳性)的一些情况。然而,这可能发生的类层次结构是层次结构,我说你不应该创建(即包含多个类型B的间接基地的派生类)。您可以通过交换角色a
和b
再次测试来减少漏报次数(然后仅当均为A
和B
在最派生的类中不明确时,测试将失败)。
您还可以结合你的和我的测试给出三种结果:
- 这两项测试成功:指针肯定是同一对象(或诺斯空)。
- 两个测试都失败:指针绝对不是同一个对象。
- 只有我的测试失败:要么您的测试给出了假阳性,或我的测试给出了一个假阴性。你不能确定两者是否是同一个对象,但至少你可以告诉你说不出来。
为什么不'a == b'? – iammilind 2012-04-02 10:24:00
@iammilind:A和B可能是一些D的基类,但彼此无关 – user396672 2012-04-02 10:27:02
@iammilind的+1 - 旧的'uns是最好的! – 2012-04-02 10:27:15