Почему вектор удаляет деструктор, называемый в результате скаляра, удаляют?

У меня есть некоторый код, который отказывает в большой системе. Однако код по существу сводится к следующему псевдокоду. Я удалил большую часть детали, поскольку я попытался свести это к скелету; я не думаю, что это пропускает что-либо решающее все же.

// in a DLL:

#ifdef _DLL
#define DLLEXP __declspec(dllexport)
#else
#define DLLEXP __declspec(dllimport)
#endif

class DLLEXP MyClass // base class; virtual
{
public:
  MyClass() {};
  virtual ~MyClass() {};

  some_method () = 0; // pure virtual

  // no member data
};

class DLLEXP MyClassImp : public MyClass
{
public:
  MyClassImp( some_parameters )
  { 
    // some assignments...
  }

  virtual ~MyClassImp() {};

private:
  // some member data...
};

и:

// in the EXE:

MyClassImp* myObj = new MyClassImp ( some_arguments ); // scalar new
// ... and literally next (as part of my cutting-down)...
delete myObj; // scalar delete

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

В Отладочная сборка в Visual Studio (2008 Pro), в Microsoft , следующие сбои утверждения:

_ASSERTE(_CrtIsValidHeapPointer(pUserData));

Около вершины стека следующие объекты:

mydll_d.dll!operator delete()
mydll_d.dll!MyClassImp::`vector deleting destructor'()

Я думаю, что это должно быть

mydll_d.dll!MyClassImp::`scalar deleting destructor'()

Таким образом, программа ведет себя, как будто я записал

MyClassImp* myObj = new MyClassImp ( some_arguments );
delete[] newObj; // array delete

Адрес в pUserData тот из myObj самостоятельно (в противоположность участнику). Память вокруг того адреса похожа на это:

                                ... FD FD FD FD
(address here)
VV VV VV VV MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
FD FD FD FD AB AB AB AB AB AB AB AB EE FE EE FE
...

где четыре VVs являются, по-видимому, адресом таблицы виртуальной функции, MM...MM опознаваемые членские данные, и другие байты являются различными специальными маркерами, помещенными на месте отладчиком (например, FD FDs являются 'защитными байтами' вокруг устройства хранения данных объекта).

Незадолго до отказа утверждения я действительно вижу VVs изменение, и задаются вопросом, происходит ли это из-за переключателя к таблице виртуальной функции базового класса.

Я знаю о проблеме неправильного уровня в разрушении перенесения иерархии классов. Это не проблема здесь; мои деструкторы являются все виртуальными.

Я отмечаю страницу "BUG: Wrong Operator Delete Called for Exported Class" Microsoft http://support.microsoft.com/kb/122675, но это, кажется, расценивает неправильный исполняемый файл (с неправильной "кучей") пытающийся взять на себя ответственность за разрушение данных.

В моем случае случается так, что неправильный 'аромат' удаления деструктора, кажется, применяется: т.е. вектор, а не скаляр.

Я нахожусь в процессе попытки произвести минимальный код сокращения, который все еще показывает проблему.

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

Возможно, самая большая подсказка здесь mydll_d.dll!operator delete() на стеке. Если я ожидаю, что это будет myexe_d.exe!operator delete(), указание, что DLLEXPs были 'потеряны'?

Я предполагаю, что это могло быть экземпляром двойного - удаляют (но я не думаю так).

Есть ли хорошая ссылка, которую я могу считать относительно какой _CrtIsValidHeapPointer проверки на?

11
задан Rhubbarb 30 July 2010 в 16:05
поделиться

3 ответа

Похоже, это может быть проблема выделения одной кучи и попытки удаления на другой. Это может быть проблемой при выделении объектов из библиотеки DLL, поскольку у библиотеки есть собственная куча. Из кода, который вы показываете, не похоже, что это будет проблемой, но, может быть, при упрощении что-то было потеряно? Раньше я видел, как этот код использует фабричные функции и виртуальные методы destroy для объектов, чтобы гарантировать, что выделение и удаление происходит в коде dll.

8
ответ дан 3 December 2019 в 09:40
поделиться

Microsoft предоставляет исходный код для их среды выполнения C; вы можете проверить там, что делает _CrtIsValidHeapPointer . В моей установке он находится в C: \ Program Files (x86) \ Microsoft Visual Studio 10.0 \ VC \ crt \ src \ dbgheap.c .

Еще одно предложение - проверить дизассемблирование

delete newObj; // scalar delete

и сравнить его с дизассемблированием, созданным для

delete[] newObj;

и

delete pointerToClassLikeMyClassThatIsInExeAndNotDll;

, чтобы проверить вашу теорию о вызове delete [] . Точно так же вы можете проверить стек вызовов для

delete pointerToClassLikeMyClassThatIsInExeAndNotDll;

, чтобы проверить свою теорию о mydll_d.dll! Operator delete () по сравнению с myexe_d.exe! Operator delete () .

1
ответ дан 3 December 2019 в 09:40
поделиться

Спасибо за все ответы и комментарии. Все они были полезны и актуальны.

Любая дополнительная информация по-прежнему приветствуется.


Следующий комментарий на мой вопрос от Hans Passant:

Как только вы начинаете экспортировать классы из DLL, компиляция с /MD становится очень важной. По-моему, это похоже на /MT.

В результате этого я внимательнее присмотрелся к настройке связей во всем проекте. Я обнаружил "похороненные" экземпляры /MT и /MTd, которые должны были быть /MD и /MDd, плюс некоторые связанные с этим несоответствия в других настройках.

Исправив их, утверждение теперь не выбрасывается, и код, похоже, ведет себя правильно.


Вот некоторые вещи, которые следует проверить при возникновении сбоев или отказов утверждений при выходе из диапазонов выполнения и вызове деструкторов. Убедитесь, что во всех проектах (включая зависимости) и во всех конфигурациях (особенно в проблемной):

(Здесь пути *.vcproj относительны к .)

  • Правильная среда выполнения выбрана в разделе C/C++ | Code Generation | Runtime Library ;
  • Соответствующие определения (если таковые имеются) сделаны в разделе C/C++ | Preprocessor | Preprocessor Definitions особенно в отношении использования статических против динамических библиотек (например, _STLP_USE_STATIC_LIB против _STLP_USE_DYNAMIC_LIB для STLport);
  • Соответствующие версии библиотек выбираются в разделе Linker | Input | Additional Dependencies <Инструмент[@Name="VCLinkerTool"]/@AdditionalDependencies> особенно в отношении статических библиотек времени выполнения против "оберток" для библиотек DLL (например, stlport_static.lib против stlport. N.M.lib).

Интересно, что скалярный "аромат" удаления, который я ожидал, все еще не вызывается (точка останова не достигается). То есть, я по-прежнему вижу только векторный деструктор удаления. Поэтому, возможно, это была "красная селедка".

Возможно, это просто проблема реализации Microsoft, или, возможно, есть еще какая-то тонкость, которую я упустил.

1
ответ дан 3 December 2019 в 09:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: