Что происходит с деструктором базового класса, если деструктор производного класса выдает исключение - PullRequest
23 голосов
/ 22 декабря 2010

Мне просто стало интересно, как освободить ресурсы в следующем случае.

class Base {
  Resource *r;

public:
  Base() { /* ... */ }
  ~Base() {
    delete r; 
  }
};

class Derived : public Base {
public:
  Derived() { /* ... */ }
  ~Derived() {
    /* Suddenly something here throws! */
  }
};

int main() {
  try {
    Derived d;
  } catch(...) {
    /* what happened with Base::r !? */
  }
}

Будет ли вызываться деструктор базового класса, если генерирует деструктор производного класса?Или будет утечка?

Ответы [ 3 ]

20 голосов
/ 22 декабря 2010

Согласно §15.2 / 2:

Объект, который частично построен или частично разрушен, будет иметь деструкторы, выполненные для всех полностью построенных подобъектов, то есть для подобъектов, для которых конструктор завершил выполнение, а деструктор еще не начал выполнение.

Таким образом, деструктор базового класса должен быть вызван. То есть, как мы знаем, это очистит базовый класс:

#include <iostream>

struct foo
{
    ~foo()
    {
        std::cout << "clean" << std::endl;
    }
};

struct bar : foo
{
    bar()
    { // foo is initialized...
        throw 0; // ...so its destructor is run
    }
};

int main()
{
    try
    {
        bar b;
    }
    catch (...)
    {
        std::cerr << "caught" << std::endl;
    }
}

И что это очистит член:

#include <iostream>

struct foo
{
    ~foo()
    {
        std::cout << "clean" << std::endl;
    }
};

struct bar
{
    ~bar()
    { // f has been initialized...
        throw 0; // ...so its destructor will run
    }

    foo f;
};

int main()
{
    try
    {
        bar b;
    }
    catch (...)
    {
        std::cerr << "caught" << std::endl;
    }
}

Это также очистит базовый класс:

#include <iostream>

struct foo
{
    ~foo()
    {
        std::cout << "clean" << std::endl;
    }
};

struct bar : foo
{
    ~bar()
    { // foo has been initialized...
        throw 0; // ...so its destructor will run
    }
};

int main()
{
    try
    {
        bar b;
    }
    catch (...)
    {
        std::cerr << "caught" << std::endl;
    }
}

Это мое понимание цитаты.

1 голос
/ 22 декабря 2010

Деструктор базового класса действительно называется. Пример кода:

#include 
#include 

class Base {
public:
  Base() { /* ... */ }
  ~Base() {
    printf("Base\n");
  }
};

class Derived : public Base {
public:
  Derived() { /* ... */ }
  ~Derived() {
    printf("Derived\n");
    throw 1;
  }
};

int main() {
  try {
    Derived d;
  } catch(...) {
    printf("CAUGHT!\n");
  }
}

Это печатает:

Derived
Base
CAUGHT!
1 голос
/ 22 декабря 2010

Будет вызван базовый деструктор.

В Effective C ++ Мейерс рекомендует, чтобы исключения не оставляли деструкторов.Поймай исключение внутри деструктора и обработай его, проглоти или прекрати.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...