Вызов функции-члена изнутри перегруженного оператора удалить? - PullRequest
5 голосов
/ 25 марта 2011

Эта статья о Бинарно-совместимых интерфейсах C ++ содержит код:

class Window {
public:
  // ...
  virtual void destroy() = 0;

  void operator delete(void* p) {
    if (p) {
      Window* w = static_cast<Window*>(p);
      w->destroy(); // VERY BAD IDEA
    }
  }
};

Мне кажется, что это неправильно: operator delete() работает на raw memory с целью его освобождения.Деструктор объекта уже был вызван, поэтому вызов destroy() работает с "фантомным" объектом (если он вообще работает).Действительно: вот почему operator delete() принимает void*, а не Window* (в данном случае).

Итак, дизайн имеет недостатки, верно?(Если это правильно, почему это правильно?)

Ответы [ 3 ]

6 голосов
/ 25 марта 2011

Я согласен (если Window::destroy не является статической функцией-членом):

3.8p1: время жизни объекта типа T заканчивается, если: если T является типом класса с нетривиальным деструктором, начинается вызов деструктора или [...]

3.8p5: [...] После окончания срока службы объекта и до повторного использования или освобождения хранилища, которое занимал объект, любой указатель, который ссылается на место хранения, где был расположен объект [...] могут быть использованы, но только в ограниченном количестве. ... Если объект будет или был не класса класса POD, программа имеет неопределенное поведение if: указатель используется для доступа к нестатическому члену данных или вызова нестатического члена функция объекта, или [...]

(акцент мой)

0 голосов
/ 25 марта 2011

Это действительно неприятный код, пытающийся быть полезным.

В статье говорится, что в коде COM не следует delete объект, а вместо этого вызывайте obj->destroy(). Таким образом, чтобы быть «полезным», автор заставляет оператора delete делать вызов уничтожения. Противный!

Гораздо лучше было бы просто объявить удаление частного оператора, поэтому пользователь не может удалять объекты и вместо этого должен найти правильный путь.

0 голосов
/ 25 марта 2011

Да, этот код (если он помечен как C ++) очень неправильный.

Оператор new и удаление, как вы говорите, обработки необработанной памяти, а не объектов.

Однако эта статья посвящена конкретным компиляторам и конкретным проблемам реализации, поэтому может случиться так, что в этом ограниченном контексте код работает ... более того, MS не очень хорошо известна тем, насколько хорошо они заботятся о переносимом C ++ (на самом деле, наоборот) так что может быть , такого рода плохой код (или был в 2002 году) на самом деле не только работает, но даже является разумным решением.

...