Hatred's Log Place

DON'T PANIC!

Заметки об отладке

Mar 28, 2013 - 2 minute read

Обращение к полям абстрактного класса

Суть, есть базовый абстрактный класс (не пишу виртуальные деструкторы, полагаем это само сабой разумеющимся):

class Base
{
public:
  virtual void foo() = 0;
};

Есть какая-то реализация этого абстрактного класса:

class Impl : public Base
{
public:
  void foo()
  {
    std::cout << "Impl::foo()" << std::endl;
  }
};

Проблема может возникнуть в таком коде:

class SomeClass
{
public:
  SomeClass()
  {
    init();
  }
  
  ~SomeClass()
  {
    delete ptr;
  }
  
  void call()
  {
    ptr->foo();
  }
  
private:
  void init()
  {
    if (ptr == 0)
      ptr = new Impl();
  }

  Base *ptr;
};

Видите проблему? Что произойдёт когда вы вызовете метод call() у экземпляра класса SomeClass? Что произойдёт когда вы попытаетесь разрушить экзампляр класса SomeClass?

Ответы на два последних вопроса: неожиданное поведение, в большинстве случаев - segmemtation fault. Ответ на вопрос “почему так происходит?” вытекает из ответа на первый вопрос: мы забыли присвоить ptr значение 0 и на момент вызова init() она может быть равно чему угодно, как результат, вызова ptr = new Impl() может и не быть, а значит и указатель в таблице виртуальных функций для foo тоже может глядеть куда угодно.

В gdb в таких случаях мы можем наблюдать подобный вывод:

warning: can't find linker symbol for virtual table for 'Base' value

((При запуске отладки из Qt Creator’а первого слова warning: не будет, а в окне Locals and Expressions вы не сможете просмотреть иерархию “битого” экземпляра, либо увидите кашу в секции [vptr]))

kodar2012 laptop

comments powered by Disqus