как проверить, указывают ли два указателя на один и тот же объект или нет?

Рассмотрим два указателя

A* a; 
B* b;

И A, и B являются полиморфными классами. Как проверить, указывают ли a и b на один и тот же объект или нет?

Точнее, давайте укажем, что a и b указывают на один и тот же объект, если существует некоторый объект d типа D, такой что оба *a и *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 должен располагаться перед этим членом, стандарт не предписывает виртуальные таблицы и ничего не говорит о структуре класса.

Итак, мои вопросы:

  1. Правильно ли предложенное решение с общепринятой точки зрения?

  2. Есть ли какие-либо предостережения относительно частного (защищенного) наследования или квалификации cv?

  3. Есть ли решения получше?

[EDIT]

Я попытался представить пример, который иллюстрирует относительно сложный сценарий. В этом случае динамическая перекрестная передача и статическая передача неоднозначны.

 // 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");
  }
}
14
задан q-l-p 13 November 2017 в 20:58
поделиться