Я попытаюсь объяснить мою проблему на примере.
У меня есть следующий класс:
__declspec(dllexport) class myclass
{
public:
int a;
int b;
myclass() {};
virtual ~myclass() {};
// ~myclass() {};
};
myclass используется внутри DLL, который содержит только определение класса Test (который на самом деле является просто интерфейсом для методов foo1 и foo2 ):
class Test
{
public:
void foo1 (std::vector<myclass>& val);
std::vector<myclass> foo2 ();
};
extern "C"
{
__declspec(dllexport) bool foo1(std::vector<myclass>& val)
{
val.clear();
myclass tmp;
val.push_back(tmp);
val.push_back(tmp);
val.push_back(tmp); //just an example!
return true;
}
__declspec(dllexport) std::vector<myclass> foo2()
{
std::vector<myclass> val;
myclass tmp;
val.push_back(tmp);
val.push_back(tmp);
val.push_back(tmp); //just an example!
return val;
}
}
Главное приложение открывает DLL и вызывает методы интерфейса для получения вектора, заполненного методами foo1 или foo2 .
typedef void (*FNPTR1)(std::vector<myclass>& val);
typedef std::vector<myclass> (*FNPTR2)();
int main()
{
if (0)
{
HINSTANCE hInst = LoadLibrary(L"C:\\software\\mydll.dll");
if (!hInst) { std::cout << "\nCould Not Load the Library"; return EXIT_FAILURE; }
FNPTR1 fn = (FNPTR1)GetProcAddress(hInst, "foo1");
if (!fn) { std::cout << "\nCould not locate the function"; return EXIT_FAILURE; }
std::vector<myclass> tmp;
fn(tmp);
FreeLibrary(hInst);
tmp.clear(); //crash here!
}
if (1)
{
HINSTANCE hInst = LoadLibrary(L"C:\\software\\mydll.dll");
if (!hInst) { std::cout << "\nCould Not Load the Library"; return EXIT_FAILURE; }
FNPTR2 fn = (FNPTR2)GetProcAddress(hInst, "foo2");
if (!fn) { std::cout << "\nCould not locate the function"; return EXIT_FAILURE; }
std::vector<myclass> tmp;
tmp = fn();
FreeLibrary(hInst);
tmp.clear(); //crash here!
}
return 1;
}
}
К сожалению, случается, что в обоих случаях (используя foo1 или foo2 ) я получаю "Чтение нарушения доступа XXXX" ошибка, когда я пытаюсь очистить (или выполнить любую другую операцию) вектор tmp после выгрузки DLL.
Эта проблема возникает, только если деструктор myclass является виртуальным .
В моем приложении myclass генерируется автоматически, и мне не разрешено изменять определение деструктора. Тем не менее, я могу свободно изменять методы интерфейса dll (например, foo1 / foo2), если на этом уровне существует какое-либо решение.
Мне также интересно, можно ли как-то сказать системе использовать для tmp векторная куча основной программы вместо той, которая используется .dll.
В настоящее время я использую Visual Studio c ++ 2017 и мне разрешено использовать стандарт C ++ 11 (или более поздний)
Спасибо за вашу помощь.
Отвечая на комментарии ниже:
- Да, exe и dll скомпилированы с использованием одной и той же цепочки инструментов. Я использую параметр / MD. Пожалуйста, скажите мне, если я должен проверить дополнительные вещи.
Что касается комментария о происхождении myclass , я попробовал также все четыре возможные комбинации с базовым классом myclassbase и myclass , полученные из него:
1- myclassbase со стандартным деструктором и myclass со стандартным деструктором -> ok
2- myclassbase со стандартным деструктором и myclass свиртуальный деструктор -> crash
3- myclassbase с виртуальным деструктором и myclass со стандартным деструктором -> crash
4- myclassbase с виртуальным деструктором и myclass с виртуальным деструктором -> crash
Следовательно, я могу сделать вывод, что наличия одного виртуального деструктора достаточно для генерации вопроса.