Нарушение доступа к виртуальному деструктору базового класса - PullRequest
0 голосов
/ 03 декабря 2009

Извините, если об этом уже спрашивали, но мне было трудно искать деструктор и нарушение прав доступа =)

Вот псевдокод C ++ сценария:


В DLL1 (скомпилировано с / MT)

class A
{
public:
    virtual ~A()      <== if "virtual" is removed, everthing works OK
    {
    }
}

class B : public A
{
public:
    __declspec( dllexport ) ~B()  // i did try without exporting the destructor as well
     {
     }      <== Access Violation as it returns (if fails in assembly at delete operator...)
}

В DLL2, которая ссылается на DLL1

main()enter code here
{
    B* b = new B();
    delete b;           <== Access Violation
}

Что происходит? У меня есть мозговой шарт? Если я делаю деструктор А не виртуальным, все работает нормально - даже вызывается деструктор А и В (как если бы деструктор А был виртуальным - это из-за того, что он публичный?).

Мой главный вопрос - почему возникает нарушение прав доступа, когда деструктор базового класса объявляется виртуальным?

Ответы [ 2 ]

1 голос
/ 04 декабря 2009

Спасибо, ребята! Спасибо ChrisW .. похоже, именно это и происходит. Единственное, что мне нужно было добавить, это статический распределитель (static createNew ()):

class A
{
public:
  __declspec( dllexport ) static void destroy(A* self) { delete self; }
protected:
  virtual ~A() {}
};

class B : public A
{
 protected: 
   B();
 public:
   __declspec( dllexport ) static B* createNew() { return new B(); }
}

int main()
{
  B* b = B::createNew()
  A::destroy(b); //instead of delete b
  return 0;
}

(кстати, компиляция с / MD не подходит для меня, учитывая мою среду развертывания)

0 голосов
/ 03 декабря 2009

Поскольку происходит сбой в операторе удаления, и поскольку вы сказали, что компилируете с /MT, я считаю, что причина в том, что ваши две библиотеки DLL не разделяют одну и ту же кучу: потому что каждая из них ссылается на статическая библиотека, каждый из которых получает свою собственную копию кучи во время выполнения; и вы эффективно выделяете память в одной DLL из одной кучи и удаляете память в другой DLL из другой кучи.

Чтобы обойти это, вы можете объявить, что деструктор защищен, и не экспортировать его. Вместо этого создайте статическую функцию уничтожения:

class A
{
public:
  __declspec( dllexport ) static void destroy(A* self) { delete self; }
protected:
  virtual ~A() {}
};

int main()
{
  B* b = new B();
  A::destroy(b); //instead of delete b
  return 0;
}

В качестве альтернативы, и вы можете предпочесть это, потому что это не связано с изменением исходного кода, убедитесь, что обе библиотеки DLL собраны с использованием одной и той же кучи, то есть с использованием версий DLL среды выполнения C, что, я думаю, означает использование Опция /MD вместо /MT.

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